diff --git a/private/app.te b/private/app.te
index e87f8df5b69b460f9aaba6c05dd8fc7200df644a..e0fb6f14d86696aaad672c31e565f1f218a1f156 100644
--- a/private/app.te
+++ b/private/app.te
@@ -255,6 +255,12 @@ allow appdomain proc_meminfo:file r_file_perms;
 # For app fuse.
 allow appdomain app_fuse_file:file { getattr read append write };
 
+use_pdx({ appdomain -isolated_app -ephemeral_app }, surfaceflinger)
+use_pdx({ appdomain -isolated_app -ephemeral_app }, sensord)
+use_pdx({ appdomain -isolated_app -ephemeral_app }, performanced)
+# TODO: apps do not directly open the IPC socket for bufferhubd.
+use_pdx({ appdomain -isolated_app -ephemeral_app }, bufferhubd)
+
 ###
 ### CTS-specific rules
 ###
diff --git a/private/bufferhubd.te b/private/bufferhubd.te
new file mode 100644
index 0000000000000000000000000000000000000000..4fa77a59b3aff645540d07bb426bc427f7074570
--- /dev/null
+++ b/private/bufferhubd.te
@@ -0,0 +1 @@
+init_daemon_domain(bufferhubd)
diff --git a/private/file_contexts b/private/file_contexts
index 8584758fe2ba0ac288534bfa9bfc4b841260aacd..3378456498049989f74e3ec4b87c58b99dd3c515 100644
--- a/private/file_contexts
+++ b/private/file_contexts
@@ -124,6 +124,7 @@
 /dev/socket/mdnsd	u:object_r:mdnsd_socket:s0
 /dev/socket/mtpd	u:object_r:mtpd_socket:s0
 /dev/socket/netd	u:object_r:netd_socket:s0
+/dev/socket/pdx(/.*)?	u:object_r:pdx_socket:s0
 /dev/socket/property_service	u:object_r:property_socket:s0
 /dev/socket/racoon	u:object_r:racoon_socket:s0
 /dev/socket/rild	u:object_r:rild_socket:s0
@@ -176,6 +177,9 @@
 /system/bin/servicemanager	u:object_r:servicemanager_exec:s0
 /system/bin/hwservicemanager	u:object_r:hwservicemanager_exec:s0
 /system/bin/surfaceflinger	u:object_r:surfaceflinger_exec:s0
+/system/bin/bufferhubd	u:object_r:bufferhubd_exec:s0
+/system/bin/performanced	u:object_r:performanced_exec:s0
+/system/bin/sensord	u:object_r:sensord_exec:s0
 /system/bin/drmserver	u:object_r:drmserver_exec:s0
 /system/bin/dumpstate   u:object_r:dumpstate_exec:s0
 /system/bin/incident   u:object_r:incident_exec:s0
@@ -241,6 +245,7 @@
 /system/bin/storaged             u:object_r:storaged_exec:s0
 /system/bin/webview_zygote32     u:object_r:webview_zygote_exec:s0
 /system/bin/webview_zygote64     u:object_r:webview_zygote_exec:s0
+/system/bin/virtual_touchpad     u:object_r:virtual_touchpad_exec:s0
 /system/bin/hw/android\.hardware\.audio@2\.0-service          u:object_r:hal_audio_default_exec:s0
 /system/bin/hw/android\.hardware\.biometrics\.fingerprint@2\.1-service u:object_r:hal_fingerprint_default_exec:s0
 /system/bin/hw/android\.hardware\.bluetooth@1\.0-service      u:object_r:hal_bluetooth_default_exec:s0
diff --git a/private/performanced.te b/private/performanced.te
new file mode 100644
index 0000000000000000000000000000000000000000..9544f662c1f5466dc5bac166320152e37cb9d8a5
--- /dev/null
+++ b/private/performanced.te
@@ -0,0 +1 @@
+init_daemon_domain(performanced)
diff --git a/private/sensord.te b/private/sensord.te
new file mode 100644
index 0000000000000000000000000000000000000000..ef03b095cb4d4b7cb6b22856cfceb4b5df1df6bf
--- /dev/null
+++ b/private/sensord.te
@@ -0,0 +1 @@
+init_daemon_domain(sensord)
diff --git a/private/service_contexts b/private/service_contexts
index 607d12b9159dde53cb657fdc68a3fe697ebc8f60..3b01c0b8d88f3ed379b48c5fc2b6eda5dd8713c4 100644
--- a/private/service_contexts
+++ b/private/service_contexts
@@ -152,6 +152,7 @@ usagestats                                u:object_r:usagestats_service:s0
 usb                                       u:object_r:usb_service:s0
 user                                      u:object_r:user_service:s0
 vibrator                                  u:object_r:vibrator_service:s0
+virtual_touchpad                          u:object_r:virtual_touchpad_service:s0
 voiceinteraction                          u:object_r:voiceinteraction_service:s0
 vrmanager                                 u:object_r:vr_manager_service:s0
 wallpaper                                 u:object_r:wallpaper_service:s0
diff --git a/private/surfaceflinger.te b/private/surfaceflinger.te
index 3cf6be357e5aae827a4b6a81d60370db7b0038f1..a4009133e5efa1063cd34bf4ab1470ca5351e33f 100644
--- a/private/surfaceflinger.te
+++ b/private/surfaceflinger.te
@@ -83,6 +83,13 @@ allow surfaceflinger tmpfs:dir r_dir_perms;
 allow surfaceflinger system_server:fd use;
 allow surfaceflinger ion_device:chr_file r_file_perms;
 
+# pdx IPC
+pdx_server(surfaceflinger)
+
+use_pdx(surfaceflinger, bufferhubd)
+use_pdx(surfaceflinger, performanced)
+use_pdx(surfaceflinger, sensord)
+
 ###
 ### Neverallow rules
 ###
diff --git a/private/virtual_touchpad.te b/private/virtual_touchpad.te
new file mode 100644
index 0000000000000000000000000000000000000000..ced556e263eb1d1850f4e3c8b12efb8b27f9bb14
--- /dev/null
+++ b/private/virtual_touchpad.te
@@ -0,0 +1 @@
+init_daemon_domain(virtual_touchpad)
diff --git a/public/bufferhubd.te b/public/bufferhubd.te
new file mode 100644
index 0000000000000000000000000000000000000000..95433981e9e2a23701686e45e6ca172e1df41fc0
--- /dev/null
+++ b/public/bufferhubd.te
@@ -0,0 +1,12 @@
+# bufferhubd
+type bufferhubd, domain, mlstrustedsubject;
+type bufferhubd_exec, exec_type, file_type;
+
+pdx_server(bufferhubd)
+use_pdx(bufferhubd, performanced)
+
+# Access the GPU.
+allow bufferhubd gpu_device:chr_file rw_file_perms;
+
+# Access /dev/ion
+allow bufferhubd ion_device:chr_file r_file_perms;
diff --git a/public/dumpstate.te b/public/dumpstate.te
index ab23004e900bd26b65a5575e72b37999a7d273ce..2ba0e587394ef53efebeceef4a0ae3d6cb58195d 100644
--- a/public/dumpstate.te
+++ b/public/dumpstate.te
@@ -167,7 +167,7 @@ userdebug_or_eng(`
   allow dumpstate misc_logd_file:file r_file_perms;
 ')
 
-allow dumpstate { service_manager_type -gatekeeper_service -dumpstate_service -incident_service }:service_manager find;
+allow dumpstate { service_manager_type -gatekeeper_service -dumpstate_service -incident_service -virtual_touchpad_service }:service_manager find;
 allow dumpstate servicemanager:service_manager list;
 
 allow dumpstate devpts:chr_file rw_file_perms;
diff --git a/public/file.te b/public/file.te
index 3d6b39b9d1e07b0ca1daadbe5aee98d502fc7dc7..d279748bf487e4dd2f57b756aa89076bbb8bf0b2 100644
--- a/public/file.te
+++ b/public/file.te
@@ -230,6 +230,7 @@ type mdnsd_socket, file_type, mlstrustedobject;
 type misc_logd_file, file_type;
 type mtpd_socket, file_type;
 type netd_socket, file_type;
+type pdx_socket, file_type, mlstrustedobject;
 type property_socket, file_type, mlstrustedobject;
 type racoon_socket, file_type;
 type rild_socket, file_type;
diff --git a/public/performanced.te b/public/performanced.te
new file mode 100644
index 0000000000000000000000000000000000000000..8f9d16b05757ce313f31f1208117d6b34d42f65d
--- /dev/null
+++ b/public/performanced.te
@@ -0,0 +1,18 @@
+# performanced
+type performanced, domain, mlstrustedsubject;
+type performanced_exec, exec_type, file_type;
+
+pdx_server(performanced)
+
+# TODO: use file caps to obtain sys_nice instead of setuid / setgid.
+allow performanced self:capability { setuid setgid sys_nice };
+
+# Access /proc to validate we're only affecting threads in the same thread group.
+# Performanced also shields unbound kernel threads.  It scans every task in the
+# root cpu set, but only affects the kernel threads.
+r_dir_file(performanced, { appdomain bufferhubd kernel sensord surfaceflinger })
+dontaudit performanced domain:dir read;
+allow performanced { appdomain bufferhubd kernel sensord surfaceflinger }:process setsched;
+
+# Access /dev/cpuset/cpuset.cpus
+r_dir_file(performanced, cgroup)
diff --git a/public/sensord.te b/public/sensord.te
new file mode 100644
index 0000000000000000000000000000000000000000..bffe3cda4359f6a3c6c8f056a1ebad51481a66d9
--- /dev/null
+++ b/public/sensord.te
@@ -0,0 +1,20 @@
+# sensord
+type sensord, domain, mlstrustedsubject;
+type sensord_exec, exec_type, file_type;
+
+pdx_server(sensord)
+use_pdx(sensord, bufferhubd)
+use_pdx(sensord, performanced)
+
+# Access /dev/ion
+allow sensord ion_device:chr_file r_file_perms;
+
+allow sensord sensors_device:chr_file rw_file_perms;
+
+binder_use(sensord)
+binder_call(sensord, system_server)
+allow sensord system_server:unix_stream_socket { read write };
+
+allow sensord sensorservice_service:service_manager find;
+# permission_service is used by the NDK sensor APIs.
+allow sensord permission_service:service_manager find;
diff --git a/public/service.te b/public/service.te
index 677124820499a49ace6766e035c259a9fb495f12..7ef2711844f2e4e2caf5d139d83652567a0f2846 100644
--- a/public/service.te
+++ b/public/service.te
@@ -25,6 +25,7 @@ type storaged_service,          service_manager_type;
 type surfaceflinger_service,    service_manager_type;
 type system_app_service,        service_manager_type;
 type update_engine_service,     service_manager_type;
+type virtual_touchpad_service,  service_manager_type;
 
 # system_server_services broken down
 type accessibility_service, app_api_service, system_server_service, service_manager_type;
diff --git a/public/shell.te b/public/shell.te
index 73f837e0fe9f9de9865c5be694abc0a347f7f5e3..fb40b9580af353b81b2282558b806526dbb90ad0 100644
--- a/public/shell.te
+++ b/public/shell.te
@@ -82,7 +82,7 @@ allow shell servicemanager:service_manager list;
 # don't allow shell to access GateKeeper service
 # TODO: why is this so broad? Tightening candidate? It needs at list:
 # - dumpstate_service (so it can receive dumpstate progress updates)
-allow shell { service_manager_type -gatekeeper_service -incident_service -installd_service -netd_service }:service_manager find;
+allow shell { service_manager_type -gatekeeper_service -incident_service -installd_service -netd_service -virtual_touchpad_service }:service_manager find;
 allow shell dumpstate:binder call;
 
 # allow shell to get information from hwservicemanager
diff --git a/public/te_macros b/public/te_macros
index c9ab6e0cced0700036a975a899fa46757dbc7e93..7a9eeb660eba6ad3ace7fdd66c79418c1f004122 100644
--- a/public/te_macros
+++ b/public/te_macros
@@ -81,6 +81,32 @@ allow $1 $1_tmpfs:file { read write };
 allow $1 tmpfs:dir { getattr search };
 ')
 
+# pdx macros for IPC. pdx is a high-level name which contains transport-specific
+# rules from underlying transport (e.g. UDS-based implementation).
+
+#####################################
+# pdx_server(domain)
+define(`pdx_server', `
+allow $1 pdx_socket:dir create_dir_perms;
+allow $1 pdx_socket:sock_file create_file_perms;
+')
+
+#####################################
+# use_pdx(clientdomain, serverdomain)
+define(`use_pdx', `
+# Open the socket.
+allow $1 pdx_socket:dir r_dir_perms;
+allow $1 pdx_socket:sock_file rw_file_perms;
+# Use the socket.
+allow $1 $2:unix_stream_socket { connectto read write shutdown };
+# Clients recieve an event fd from the server.
+allow $1 $2:fd use;
+# Servers may receive sync fences, gralloc buffers, etc, from clients.
+# This could be tightened on a per-server basis, but keeping track of service
+# clients is error prone.
+allow $2 $1:fd use;
+')
+
 #####################################
 # init_daemon_domain(domain)
 # Set up a transition from init to the daemon domain
diff --git a/public/virtual_touchpad.te b/public/virtual_touchpad.te
new file mode 100644
index 0000000000000000000000000000000000000000..92d5c274a2fcb45b0c9ff4c003a5519b780a7957
--- /dev/null
+++ b/public/virtual_touchpad.te
@@ -0,0 +1,12 @@
+type virtual_touchpad, domain;
+type virtual_touchpad_exec, exec_type, file_type;
+
+binder_use(virtual_touchpad)
+binder_service(virtual_touchpad)
+add_service(virtual_touchpad, virtual_touchpad_service)
+
+# Requires access to /dev/uinput to create and feed the virtual device.
+allow virtual_touchpad uhid_device:chr_file { w_file_perms ioctl };
+
+# Limit access so that nothing else can inject input.
+neverallow { domain -system_app -virtual_touchpad } virtual_touchpad_service:service_manager find;