diff --git a/docs/html/config_access.html b/docs/html/config_access.html
index e62900b7..a27e2892 100644
--- a/docs/html/config_access.html
+++ b/docs/html/config_access.html
@@ -93,6 +93,10 @@ The columns have the following functions:
   <dd>
   Enables access to video recording functions for the HTSP protocol (Showtime, XBMC etc.).
 
+  <dt><b>All DVR</b>
+  <dd>
+  Enable to access to DVR entries created by other users (read-only).
+
   <dt><b>DVR Config Profile</b>
   <dd>
   If set, the user will only be able to use the DVR config profile
diff --git a/src/access.c b/src/access.c
index 721dd7e9..4d68338e 100644
--- a/src/access.c
+++ b/src/access.c
@@ -357,16 +357,17 @@ access_dump_a(access_t *a)
   int first;
 
   snprintf(buf, sizeof(buf),
-    "%s:%s [%s%s%s%s%s%s%s], conn=%u, chmin=%llu, chmax=%llu%s",
+    "%s:%s [%c%c%c%c%c%c%c%c], conn=%u, chmin=%llu, chmax=%llu%s",
     a->aa_representative ?: "<no-id>",
     a->aa_username ?: "<no-user>",
-    a->aa_rights & ACCESS_STREAMING          ? "S" : "",
-    a->aa_rights & ACCESS_ADVANCED_STREAMING ? "A" : "",
-    a->aa_rights & ACCESS_HTSP_STREAMING     ? "T" : "",
-    a->aa_rights & ACCESS_WEB_INTERFACE      ? "W" : "",
-    a->aa_rights & ACCESS_RECORDER           ? "R" : "",
-    a->aa_rights & ACCESS_HTSP_RECORDER      ? "E" : "",
-    a->aa_rights & ACCESS_ADMIN              ? "*" : "",
+    a->aa_rights & ACCESS_STREAMING          ? 'S' : ' ',
+    a->aa_rights & ACCESS_ADVANCED_STREAMING ? 'A' : ' ',
+    a->aa_rights & ACCESS_HTSP_STREAMING     ? 'T' : ' ',
+    a->aa_rights & ACCESS_WEB_INTERFACE      ? 'W' : ' ',
+    a->aa_rights & ACCESS_RECORDER           ? 'R' : ' ',
+    a->aa_rights & ACCESS_HTSP_RECORDER      ? 'E' : ' ',
+    a->aa_rights & ACCESS_ALL_RECORDER       ? 'L' : ' ',
+    a->aa_rights & ACCESS_ADMIN              ? '*' : ' ',
     a->aa_conn_limit,
     (long long)a->aa_chmin, (long long)a->aa_chmax,
     a->aa_match ? ", matched" : "");
@@ -812,6 +813,8 @@ access_entry_update_rights(access_entry_t *ae)
     r |= ACCESS_RECORDER;
   if (ae->ae_htsp_dvr)
     r |= ACCESS_HTSP_RECORDER;
+  if (ae->ae_all_dvr)
+    r |= ACCESS_ALL_RECORDER;
   if (ae->ae_webui)
     r |= ACCESS_WEB_INTERFACE;
   if (ae->ae_admin)
@@ -846,8 +849,10 @@ access_entry_create(const char *uuid, htsmsg_t *conf)
   TAILQ_INIT(&ae->ae_ipmasks);
 
   if (conf) {
+    /* defaults */
     ae->ae_htsp_streaming = 1;
     ae->ae_htsp_dvr       = 1;
+    ae->ae_all_dvr        = 1;
     idnode_load(&ae->ae_id, conf);
     /* note password has PO_NOSAVE, thus it must be set manually */
     if ((s = htsmsg_get_str(conf, "password")) != NULL)
@@ -1297,6 +1302,12 @@ const idclass_t access_entry_class = {
       .name     = "HTSP DVR",
       .off      = offsetof(access_entry_t, ae_htsp_dvr),
     },
+    {
+      .type     = PT_BOOL,
+      .id       = "all_dvr",
+      .name     = "All DVR",
+      .off      = offsetof(access_entry_t, ae_all_dvr),
+    },
     {
       .type     = PT_STR,
       .id       = "dvr_config",
@@ -1405,6 +1416,7 @@ access_init(int createdefault, int noacl)
     ae->ae_htsp_streaming = 1;
     ae->ae_dvr            = 1;
     ae->ae_htsp_dvr       = 1;
+    ae->ae_all_dvr        = 1;
     ae->ae_webui          = 1;
     ae->ae_admin          = 1;
     access_entry_update_rights(ae);
diff --git a/src/access.h b/src/access.h
index a4aee809..22f03083 100644
--- a/src/access.h
+++ b/src/access.h
@@ -66,6 +66,7 @@ typedef struct access_entry {
 
   int ae_dvr;
   int ae_htsp_dvr;
+  int ae_all_dvr;
   struct dvr_config *ae_dvr_config;
   LIST_ENTRY(access_entry) ae_dvr_config_link;
 
@@ -119,13 +120,15 @@ typedef struct access_ticket {
 #define ACCESS_WEB_INTERFACE      (1<<3)
 #define ACCESS_RECORDER           (1<<4)
 #define ACCESS_HTSP_RECORDER      (1<<5)
-#define ACCESS_ADMIN              (1<<6)
+#define ACCESS_ALL_RECORDER       (1<<6)
+#define ACCESS_ADMIN              (1<<7)
 #define ACCESS_OR                 (1<<30)
 
 #define ACCESS_FULL \
   (ACCESS_STREAMING | ACCESS_ADVANCED_STREAMING | \
-   ACCESS_HTSP_STREAMING | ACCESS_HTSP_RECORDER | \
-   ACCESS_WEB_INTERFACE | ACCESS_RECORDER | ACCESS_ADMIN)
+   ACCESS_HTSP_STREAMING | ACCESS_WEB_INTERFACE | \
+   ACCESS_RECORDER | ACCESS_HTSP_RECORDER | \
+   ACCESS_ALL_RECORDER | ACCESS_ADMIN)
 
 /**
  * Create a new ticket for the requested resource and generate a id for it
diff --git a/src/dvr/dvr.h b/src/dvr/dvr.h
index eb5fb0d8..be8fdfb9 100644
--- a/src/dvr/dvr.h
+++ b/src/dvr/dvr.h
@@ -471,6 +471,17 @@ htsmsg_t *dvr_entry_class_pri_list(void *o);
 htsmsg_t *dvr_entry_class_config_name_list(void *o);
 htsmsg_t *dvr_entry_class_duration_list(void *o, const char *not_set, int max, int step);
 
+static inline int dvr_entry_verify(dvr_entry_t *de, access_t *a, int readonly)
+{
+  if (!a->aa_username || !de->de_owner)
+    return -1;
+  if (readonly && !access_verify2(a, ACCESS_ALL_RECORDER))
+    return 0;
+  if (strcmp(de->de_owner, a->aa_username))
+    return -1;
+  return 0;
+}
+
 /**
  *
  */
@@ -536,6 +547,15 @@ void dvr_autorec_done(void);
 
 void dvr_autorec_update(void);
 
+static inline int dvr_autorec_entry_verify(dvr_autorec_entry_t *dae, access_t *a)
+{
+  if (!a->aa_username || !dae->dae_owner)
+    return -1;
+  if (strcmp(dae->dae_owner, a->aa_username))
+    return -1;
+  return 0;
+}
+
 /**
  *
  */
@@ -571,6 +591,15 @@ void dvr_timerec_done(void);
 
 void dvr_timerec_update(void);
 
+static inline int dvr_timerec_entry_verify(dvr_timerec_entry_t *dte, access_t *a)
+{
+  if (!a->aa_username || !dte->dte_owner)
+    return -1;
+  if (strcmp(dte->dte_owner, a->aa_username))
+    return -1;
+  return 0;
+}
+
 /**
  *
  */
diff --git a/src/dvr/dvr_autorec.c b/src/dvr/dvr_autorec.c
index 3ec12a77..ccbaf5a9 100644
--- a/src/dvr/dvr_autorec.c
+++ b/src/dvr/dvr_autorec.c
@@ -369,6 +369,20 @@ dvr_autorec_entry_class_delete(idnode_t *self)
   autorec_entry_destroy((dvr_autorec_entry_t *)self, 1);
 }
 
+static int
+dvr_autorec_entry_class_perm(idnode_t *self, access_t *a, htsmsg_t *msg_to_write)
+{
+  dvr_autorec_entry_t *dae = (dvr_autorec_entry_t *)self;
+
+  if (access_verify2(a, ACCESS_OR|ACCESS_ADMIN|ACCESS_RECORDER))
+    return -1;
+  if (!access_verify2(a, ACCESS_ADMIN))
+    return 0;
+  if (dvr_autorec_entry_verify(dae, a))
+    return -1;
+  return 0;
+}
+
 static const char *
 dvr_autorec_entry_class_get_title (idnode_t *self)
 {
@@ -839,6 +853,7 @@ const idclass_t dvr_autorec_entry_class = {
   .ic_save       = dvr_autorec_entry_class_save,
   .ic_get_title  = dvr_autorec_entry_class_get_title,
   .ic_delete     = dvr_autorec_entry_class_delete,
+  .ic_perm       = dvr_autorec_entry_class_perm,
   .ic_properties = (const property_t[]) {
     {
       .type     = PT_BOOL,
diff --git a/src/dvr/dvr_db.c b/src/dvr/dvr_db.c
index f96c84c6..242d002c 100644
--- a/src/dvr/dvr_db.c
+++ b/src/dvr/dvr_db.c
@@ -1108,6 +1108,20 @@ dvr_entry_class_delete(idnode_t *self)
   dvr_entry_cancel_delete((dvr_entry_t *)self);
 }
 
+static int
+dvr_entry_class_perm(idnode_t *self, access_t *a, htsmsg_t *msg_to_write)
+{
+  dvr_entry_t *de = (dvr_entry_t *)self;
+
+  if (access_verify2(a, ACCESS_OR|ACCESS_ADMIN|ACCESS_RECORDER))
+    return -1;
+  if (!access_verify2(a, ACCESS_ADMIN))
+    return 0;
+  if (dvr_entry_verify(de, a, msg_to_write == NULL ? 1 : 0))
+    return -1;
+  return 0;
+}
+
 static const char *
 dvr_entry_class_get_title (idnode_t *self)
 {
@@ -1680,10 +1694,10 @@ const idclass_t dvr_entry_class = {
   .ic_class     = "dvrentry",
   .ic_caption   = "DVR Entry",
   .ic_event     = "dvrentry",
-  .ic_perm_def  = ACCESS_RECORDER,
   .ic_save      = dvr_entry_class_save,
   .ic_get_title = dvr_entry_class_get_title,
   .ic_delete    = dvr_entry_class_delete,
+  .ic_perm      = dvr_entry_class_perm,
   .ic_properties = (const property_t[]) {
     {
       .type     = PT_TIME,
diff --git a/src/dvr/dvr_timerec.c b/src/dvr/dvr_timerec.c
index 5d295776..f52cac41 100644
--- a/src/dvr/dvr_timerec.c
+++ b/src/dvr/dvr_timerec.c
@@ -310,6 +310,20 @@ dvr_timerec_entry_class_delete(idnode_t *self)
   timerec_entry_destroy((dvr_timerec_entry_t *)self, 1);
 }
 
+static int
+dvr_timerec_entry_class_perm(idnode_t *self, access_t *a, htsmsg_t *msg_to_write)
+{
+  dvr_timerec_entry_t *dte = (dvr_timerec_entry_t *)self;
+
+  if (access_verify2(a, ACCESS_OR|ACCESS_ADMIN|ACCESS_RECORDER))
+    return -1;
+  if (!access_verify2(a, ACCESS_ADMIN))
+    return 0;
+  if (dvr_timerec_entry_verify(dte, a))
+    return -1;
+  return 0;
+}
+
 static const char *
 dvr_timerec_entry_class_get_title (idnode_t *self)
 {
@@ -521,6 +535,7 @@ const idclass_t dvr_timerec_entry_class = {
   .ic_save       = dvr_timerec_entry_class_save,
   .ic_get_title  = dvr_timerec_entry_class_get_title,
   .ic_delete     = dvr_timerec_entry_class_delete,
+  .ic_perm       = dvr_timerec_entry_class_perm,
   .ic_properties = (const property_t[]) {
     {
       .type     = PT_BOOL,
diff --git a/src/htsp_server.c b/src/htsp_server.c
index 2206d484..fea8e6fb 100644
--- a/src/htsp_server.c
+++ b/src/htsp_server.c
@@ -910,7 +910,8 @@ htsp_build_event
       htsmsg_add_str(out, "image", ee->image);
   }
 
-  if((de = dvr_entry_find_by_event(e)) != NULL) {
+  if((de = dvr_entry_find_by_event(e)) != NULL &&
+     !dvr_entry_verify(de, htsp->htsp_granted_access, 1)) {
     htsmsg_add_u32(out, "dvrId", idnode_get_short_uuid(&de->de_id));
   }
 
@@ -1070,15 +1071,18 @@ htsp_method_async(htsp_connection_t *htsp, htsmsg_t *in)
 
   /* Send all autorecs */
   TAILQ_FOREACH(dae, &autorec_entries, dae_link)
-    htsp_send_message(htsp, htsp_build_autorecentry(dae, "autorecEntryAdd"), NULL);
+    if (!dvr_autorec_entry_verify(dae, htsp->htsp_granted_access))
+      htsp_send_message(htsp, htsp_build_autorecentry(dae, "autorecEntryAdd"), NULL);
 
   /* Send all timerecs */
   TAILQ_FOREACH(dte, &timerec_entries, dte_link)
-    htsp_send_message(htsp, htsp_build_timerecentry(dte, "timerecEntryAdd"), NULL);
+    if (!dvr_timerec_entry_verify(dte, htsp->htsp_granted_access))
+      htsp_send_message(htsp, htsp_build_timerecentry(dte, "timerecEntryAdd"), NULL);
 
   /* Send all DVR entries */
   LIST_FOREACH(de, &dvrentries, de_global_link)
-    if (htsp_user_access_channel(htsp,de->de_channel))
+    if (!dvr_entry_verify(de, htsp->htsp_granted_access, 1) &&
+        htsp_user_access_channel(htsp,de->de_channel))
       htsp_send_message(htsp, htsp_build_dvrentry(de, "dvrEntryAdd"), NULL);
 
   /* Send EPG updates */
@@ -1498,9 +1502,12 @@ htsp_method_updateDvrEntry(htsp_connection_t *htsp, htsmsg_t *in)
   if(htsmsg_get_u32(in, "id", &dvrEntryId))
     return htsp_error("Missing argument 'id'");
   
-  if( (de = dvr_entry_find_by_id(dvrEntryId)) == NULL) 
+  if((de = dvr_entry_find_by_id(dvrEntryId)) == NULL)
     return htsp_error("id not found");
 
+  if(dvr_entry_verify(de, htsp->htsp_granted_access, 1))
+    return htsp_error("User does not have access");
+
   /* Check access */
   if (!htsp_user_access_channel(htsp, de->de_channel))
     return htsp_error("User does not have access");
@@ -1539,9 +1546,12 @@ htsp_method_cancelDvrEntry(htsp_connection_t *htsp, htsmsg_t *in)
   if(htsmsg_get_u32(in, "id", &dvrEntryId))
     return htsp_error("Missing argument 'id'");
 
-  if( (de = dvr_entry_find_by_id(dvrEntryId)) == NULL)
+  if((de = dvr_entry_find_by_id(dvrEntryId)) == NULL)
     return htsp_error("id not found");
 
+  if(dvr_entry_verify(de, htsp->htsp_granted_access, 0))
+    return htsp_error("User does not have access");
+
   /* Check access */
   if (!htsp_user_access_channel(htsp, de->de_channel))
     return htsp_error("User does not have access");
@@ -1568,9 +1578,12 @@ htsp_method_deleteDvrEntry(htsp_connection_t *htsp, htsmsg_t *in)
   if(htsmsg_get_u32(in, "id", &dvrEntryId))
     return htsp_error("Missing argument 'id'");
 
-  if( (de = dvr_entry_find_by_id(dvrEntryId)) == NULL)
+  if((de = dvr_entry_find_by_id(dvrEntryId)) == NULL)
     return htsp_error("id not found");
 
+  if(dvr_entry_verify(de, htsp->htsp_granted_access, 0))
+    return htsp_error("User does not have access");
+
   /* Check access */
   if (!htsp_user_access_channel(htsp, de->de_channel))
     return htsp_error("User does not have access");
@@ -1682,6 +1695,9 @@ htsp_method_deleteAutorecEntry(htsp_connection_t *htsp, htsmsg_t *in)
   if((dae = dvr_autorec_find_by_uuid(daeId)) == NULL)
     return htsp_error("id not found");
 
+  if(dvr_autorec_entry_verify(dae, htsp->htsp_granted_access))
+    return htsp_error("User does not have access");
+
   /* Check access */
   if (!htsp_user_access_channel(htsp, dae->dae_channel))
     return htsp_error("User does not have access");
@@ -1775,6 +1791,9 @@ htsp_method_deleteTimerecEntry(htsp_connection_t *htsp, htsmsg_t *in)
   if((dte = dvr_timerec_find_by_uuid(dteId)) == NULL)
     return htsp_error("id not found");
 
+  if(dvr_timerec_entry_verify(dte, htsp->htsp_granted_access))
+    return htsp_error("User does not have access");
+
   /* Check access */
   if (!htsp_user_access_channel(htsp, dte->dte_channel))
     return htsp_error("User does not have access");
@@ -1813,9 +1832,12 @@ htsp_method_getDvrCutpoints(htsp_connection_t *htsp, htsmsg_t *in)
   if (htsmsg_get_u32(in, "id", &dvrEntryId))
     return htsp_error("Missing argument 'id'");
 
-  if( (de = dvr_entry_find_by_id(dvrEntryId)) == NULL)
+  if((de = dvr_entry_find_by_id(dvrEntryId)) == NULL)
     return htsp_error("id not found");
 
+  if(dvr_entry_verify(de, htsp->htsp_granted_access, 1))
+    return htsp_error("User does not have access");
+
   /* Check access */
   if (!htsp_user_access_channel(htsp, de->de_channel))
     return htsp_error("User does not have access");
@@ -2206,6 +2228,9 @@ htsp_method_file_open(htsp_connection_t *htsp, htsmsg_t *in)
     if(de == NULL)
       return htsp_error("DVR entry does not exist");
 
+    if (dvr_entry_verify(de, htsp->htsp_granted_access, 1))
+      return htsp_error("User does not have access");
+
     if (!htsp_user_access_channel(htsp, de->de_channel))
       return htsp_error("User does not have access");
 
@@ -2987,6 +3012,7 @@ _htsp_dvr_entry_update(dvr_entry_t *de, const char *method, htsmsg_t *msg)
   htsp_connection_t *htsp;
   LIST_FOREACH(htsp, &htsp_async_connections, htsp_async_link) {
     if (htsp->htsp_async_mode & HTSP_ASYNC_ON &&
+        !dvr_entry_verify(de, htsp->htsp_granted_access, 1) &&
         htsp_user_access_channel(htsp, de->de_channel)) {
       htsmsg_t *m = msg ? htsmsg_copy(msg)
                         : htsp_build_dvrentry(de, method);
@@ -3037,7 +3063,8 @@ _htsp_autorec_entry_update(dvr_autorec_entry_t *dae, const char *method, htsmsg_
   htsp_connection_t *htsp;
   LIST_FOREACH(htsp, &htsp_async_connections, htsp_async_link) {
     if (htsp->htsp_async_mode & HTSP_ASYNC_ON) {
-      if (dae->dae_channel == NULL || htsp_user_access_channel(htsp, dae->dae_channel)) {
+      if ((dae->dae_channel == NULL || htsp_user_access_channel(htsp, dae->dae_channel)) &&
+          !dvr_autorec_entry_verify(dae, htsp->htsp_granted_access)) {
         htsmsg_t *m = msg ? htsmsg_copy(msg)
                           : htsp_build_autorecentry(dae, method);
         htsp_send_message(htsp, m, NULL);
@@ -3089,7 +3116,8 @@ _htsp_timerec_entry_update(dvr_timerec_entry_t *dte, const char *method, htsmsg_
   htsp_connection_t *htsp;
   LIST_FOREACH(htsp, &htsp_async_connections, htsp_async_link) {
     if (htsp->htsp_async_mode & HTSP_ASYNC_ON) {
-      if (dte->dte_channel == NULL || htsp_user_access_channel(htsp, dte->dte_channel)) {
+      if ((dte->dte_channel == NULL || htsp_user_access_channel(htsp, dte->dte_channel)) &&
+          !dvr_timerec_entry_verify(dte, htsp->htsp_granted_access)) {
         htsmsg_t *m = msg ? htsmsg_copy(msg)
                           : htsp_build_timerecentry(dte, method);
         htsp_send_message(htsp, m, NULL);
diff --git a/src/webui/static/app/acleditor.js b/src/webui/static/app/acleditor.js
index 97ca4299..dd826d39 100644
--- a/src/webui/static/app/acleditor.js
+++ b/src/webui/static/app/acleditor.js
@@ -7,7 +7,7 @@ tvheadend.acleditor = function(panel, index)
     var list = 'enabled,username,password,prefix,' +
                'webui,admin,' +
                'streaming,adv_streaming,htsp_streaming,' +
-               'profile,conn_limit,dvr,htsp_dvr,dvr_config,' +
+               'profile,conn_limit,dvr,htsp_dvr,all_dvr,dvr_config,' +
                'channel_min,channel_max,channel_tag,comment';
 
     tvheadend.idnode_grid(panel, {
@@ -25,6 +25,7 @@ tvheadend.acleditor = function(panel, index)
             htsp_streaming: { width: 200 },
             dvr:            { width: 150 },
             htsp_dvr:       { width: 150 },
+            all_dvr:        { width: 150 },
             webui:          { width: 140 },
             admin:          { width: 100 },
             conn_limit:     { width: 160 },
diff --git a/src/webui/webui.c b/src/webui/webui.c
index 4dff23e9..b559e850 100644
--- a/src/webui/webui.c
+++ b/src/webui/webui.c
@@ -631,6 +631,9 @@ http_dvr_playlist(http_connection_t *hc, dvr_entry_t *de)
   if(http_access_verify(hc, ACCESS_RECORDER))
     return HTTP_STATUS_UNAUTHORIZED;
 
+  if(dvr_entry_verify(de, hc->hc_access, 1))
+    return HTTP_STATUS_NOT_FOUND;
+
   hostpath  = http_get_hostpath(hc);
   durration  = dvr_entry_get_stop_time(de) - dvr_entry_get_start_time(de);
   fsize = dvr_get_filesize(de);
@@ -1134,6 +1137,10 @@ page_dvrfile(http_connection_t *hc, const char *remain, void *opaque)
     pthread_mutex_unlock(&global_lock);
     return HTTP_STATUS_NOT_FOUND;
   }
+  if(dvr_entry_verify(de, hc->hc_access, 1)) {
+    pthread_mutex_unlock(&global_lock);
+    return HTTP_STATUS_NOT_FOUND;
+  }
 
   fname = tvh_strdupa(de->de_filename);
   content = muxer_container_type2mime(de->de_mc, 1);