diff --git a/attributes b/attributes
index 6123d6c1be12a4984cca8dbe05258aa9d81e6a79..bbc3d922b526715874d894f5542be086155bb0b5 100644
--- a/attributes
+++ b/attributes
@@ -50,6 +50,9 @@ attribute mlstrustedobject;
 # Domains that are allowed all permissions ("unconfined").
 attribute unconfineddomain;
 
+# All domains used for shells.
+attribute shelldomain;
+
 # All domains used for apps.
 attribute appdomain;
 
diff --git a/domain.te b/domain.te
index 3628f323671ecb9bea99e363b24d6e5d1478fa1e..d0e3ff43afaf034e55b2282507c795e8c50a4b9a 100644
--- a/domain.te
+++ b/domain.te
@@ -39,11 +39,11 @@ allow domain init:unix_stream_socket connectto;
 # Root fs.
 allow domain rootfs:dir r_dir_perms;
 allow domain rootfs:file r_file_perms;
-allow domain rootfs:lnk_file { read getattr };
+allow domain rootfs:lnk_file r_file_perms;
 
 # Device accesses.
 allow domain device:dir search;
-allow domain dev_type:lnk_file read;
+allow domain dev_type:lnk_file r_file_perms;
 allow domain devpts:dir search;
 allow domain device:file read;
 allow domain socket_device:dir search;
@@ -69,12 +69,12 @@ allow domain fs_type:dir getattr;
 allow domain system_file:dir r_dir_perms;
 allow domain system_file:file r_file_perms;
 allow domain system_file:file execute;
-allow domain system_file:lnk_file read;
+allow domain system_file:lnk_file r_file_perms;
 
 # Read files already opened under /data.
 allow domain system_data_file:dir { search getattr };
 allow domain system_data_file:file { getattr read };
-allow domain system_data_file:lnk_file read;
+allow domain system_data_file:lnk_file r_file_perms;
 
 # Read apk files under /data/app.
 allow domain apk_data_file:dir { getattr search };
@@ -87,7 +87,7 @@ allow domain dalvikcache_data_file:file r_file_perms;
 # Read already opened /cache files.
 allow domain cache_file:dir r_dir_perms;
 allow domain cache_file:file { getattr read };
-allow domain cache_file:lnk_file read;
+allow domain cache_file:lnk_file r_file_perms;
 
 # Read timezone related information
 r_dir_file(domain, zoneinfo_data_file)
@@ -110,6 +110,9 @@ r_dir_file(domain, cgroup)
 allow domain debugfs:dir r_dir_perms;
 allow domain debugfs:file w_file_perms;
 
+# Get SELinux enforcing status.
+selinux_getenforce(domain)
+
 # security files
 allow domain security_file:dir { search getattr };
 allow domain security_file:file getattr;
diff --git a/init_shell.te b/init_shell.te
index 696a6dcac3c08e92cd6abe92415a10e3b07858f1..8ff5c488f05311e2411a7b1c3ec9ece13b436006 100644
--- a/init_shell.te
+++ b/init_shell.te
@@ -1,4 +1,6 @@
 # Restricted domain for shell processes spawned by init
-type init_shell, domain;
+type init_shell, domain, shelldomain;
 domain_auto_trans(init, shell_exec, init_shell)
 unconfined_domain(init_shell)
+
+# inherits from shelldomain.te
diff --git a/shell.te b/shell.te
index 17031b974f522f99dbf8c2f9cbcdeb7394e4c0a5..9fd7c6d3035ef3c164704e90110e01817cb3a4d6 100644
--- a/shell.te
+++ b/shell.te
@@ -1,20 +1,12 @@
 # Domain for shell processes spawned by ADB
-type shell, domain;
+type shell, domain, shelldomain, mlstrustedsubject;
 type shell_exec, exec_type, file_type;
-unconfined_domain(shell)
 
 # Run app_process.
-# XXX Split into its own domain?
+# XXX Transition into its own domain?
 app_domain(shell)
 
-# shell is also permissive to permit setenforce.
+# userdebug/eng shell is also permissive to permit setenforce.
 permissive shell;
 
-# ndk-gdb invokes adb shell ps to find the app PID.
-r_dir_file(shell, non_system_app_set)
-
-# ndk-gdb invokes adb shell ls to check the app data dir.
-allow shell app_data_file:dir search;
-
-# ndk-gdb invokes adb shell kill -9 to kill the gdbserver.
-allow shell non_system_app_set:process sigkill;
+# inherits from shelldomain.te
diff --git a/shell_user.te b/shell_user.te
index 1eccbd6fed94b87cd01b98734916c532c12995d4..27a5cd095178b0990f1b67f03a96b5c44d62b38c 100644
--- a/shell_user.te
+++ b/shell_user.te
@@ -1,14 +1,9 @@
 # Domain for shell processes spawned by ADB
-type shell, domain;
+type shell, domain, shelldomain, mlstrustedsubject;
 type shell_exec, exec_type, file_type;
-unconfined_domain(shell)
 
 # Run app_process.
-# XXX Split into its own domain?
+# XXX Transition into its own domain?
 app_domain(shell)
 
-# ndk-gdb invokes adb shell ps to find the app PID.
-r_dir_file(shell, non_system_app_set)
-
-# ndk-gdb invokes adb shell ls to check the app data dir.
-allow shell app_data_file:dir search;
+# inherits from shelldomain.te
diff --git a/shelldomain.te b/shelldomain.te
new file mode 100644
index 0000000000000000000000000000000000000000..408e9daa3f25764adba05adc83dccbd6b3842a60
--- /dev/null
+++ b/shelldomain.te
@@ -0,0 +1,40 @@
+# Rules for all shell domains (e.g. console service and adb shell).
+
+# Access /data/local/tmp.
+allow shelldomain shell_data_file:dir create_dir_perms;
+allow shelldomain shell_data_file:file create_file_perms;
+allow shelldomain shell_data_file:file rx_file_perms;
+
+# Access sdcard.
+allow shelldomain sdcard_type:dir rw_dir_perms;
+allow shelldomain sdcard_type:file create_file_perms;
+
+# adb bugreport
+unix_socket_connect(shelldomain, dumpstate, dumpstate)
+
+allow shelldomain rootfs:dir r_dir_perms;
+allow shelldomain devpts:chr_file rw_file_perms;
+allow shelldomain tty_device:chr_file rw_file_perms;
+allow shelldomain console_device:chr_file rw_file_perms;
+allow shelldomain input_device:chr_file rw_file_perms;
+allow shelldomain system_file:file x_file_perms;
+allow shelldomain shell_exec:file rx_file_perms;
+allow shelldomain zygote_exec:file rx_file_perms;
+
+r_dir_file(shelldomain, apk_data_file)
+allow shelldomain dalvikcache_data_file:file { write setattr };
+
+# Set properties.
+unix_socket_connect(shelldomain, property, init)
+allow shelldomain shell_prop:property_service set;
+allow shelldomain ctl_dumpstate_prop:property_service set;
+
+# ndk-gdb invokes adb shell ps to find the app PID.
+r_dir_file(shelldomain, non_system_app_set)
+
+# ndk-gdb invokes adb shell ls to check the app data dir.
+allow shelldomain app_data_file:dir search;
+
+# ps and ps -Z output for app processes.
+r_dir_file(shelldomain, appdomain)
+allow shelldomain appdomain:process getattr;