diff --git a/domain.te b/domain.te
index 2af36e8112d52ec4fc72fbc8d930c88f84f3efa5..e7e0d7d6792545ee34c01ee1529ff8c2362a614e 100644
--- a/domain.te
+++ b/domain.te
@@ -209,10 +209,11 @@ neverallow domain self:capability2 mac_override;
 # Only recovery needs mac_admin to set contexts not defined in current policy.
 neverallow { domain -recovery } self:capability2 mac_admin;
 
-# Nobody should be able to load a new SELinux policy.
+# Only init should be able to load SELinux policies.
 # The first load technically occurs while still in the kernel domain,
 # but this does not trigger a denial since there is no policy yet.
-neverallow domain kernel:security load_policy;
+# Policy reload requires allowing this to the init domain.
+neverallow { domain -init } kernel:security load_policy;
 
 # Only init and the system_server can set selinux.reload_policy 1
 # to trigger a policy reload.
diff --git a/init.te b/init.te
index 4bf40f53b4e0b72227047fc0611d1e66c58e3d65..6b57098357429f35ebe5c3a75f0df1b17aea7248 100644
--- a/init.te
+++ b/init.te
@@ -122,6 +122,9 @@ allow init unlabeled:notdevfile_class_set { create_file_perms relabelfrom };
 allow init security_file:dir { create setattr };
 
 # Reload policy upon setprop selinux.reload_policy 1.
+# Note: this requires the following allow rule
+#   allow init kernel:security load_policy;
+# which can be configured on a device-by-device basis if needed.
 r_dir_file(init, security_file)
 
 # Any operation that can modify the kernel ring buffer, e.g. clear