diff --git a/file.te b/file.te
index 235ac77ed478f6529493bded0b86e4ee739c5ba8..ec4a18efa2b2e0c66ad7a48ffb12b8a2ed1ec879 100644
--- a/file.te
+++ b/file.te
@@ -39,6 +39,8 @@ type configfs, fs_type;
 type sysfs_devices_system_cpu, fs_type, sysfs_type;
 # /sys/module/lowmemorykiller
 type sysfs_lowmemorykiller, fs_type, sysfs_type;
+# /sys/module/wlan/parameters/fwpath
+type sysfs_wlan_fwpath, fs_type, sysfs_type;
 
 type sysfs_thermal, sysfs_type, fs_type;
 
@@ -228,6 +230,8 @@ type system_ndebug_socket, file_type;
 type uncrypt_socket, file_type;
 type vold_socket, file_type;
 type wpa_socket, file_type;
+# hostapd control interface.
+type hostapd_socket, file_type;
 type zygote_socket, file_type;
 type sap_uim_socket, file_type;
 # UART (for GPS) control proc file
diff --git a/file_contexts b/file_contexts
index d8e0a718ae88757e53a06b3ddb25a0c0916e870c..8106bd263512736af7534b4f4a8bedc1eab25b05 100644
--- a/file_contexts
+++ b/file_contexts
@@ -161,6 +161,7 @@
 /system/bin/dumpstate   u:object_r:dumpstate_exec:s0
 /system/bin/vold	u:object_r:vold_exec:s0
 /system/bin/netd	u:object_r:netd_exec:s0
+/system/bin/wificond	u:object_r:wificond_exec:s0
 /system/bin/rild	u:object_r:rild_exec:s0
 /system/bin/audioserver	u:object_r:audioserver_exec:s0
 /system/bin/mediadrmserver	u:object_r:mediadrmserver_exec:s0
@@ -282,7 +283,7 @@
 /data/misc/wifi(/.*)?           u:object_r:wifi_data_file:s0
 /data/misc/wifi/sockets(/.*)?   u:object_r:wpa_socket:s0
 /data/misc/wifi/sockets/wpa_ctrl.*   u:object_r:system_wpa_socket:s0
-/data/misc/wifi/hostapd(/.*)?   u:object_r:wpa_socket:s0
+/data/misc/wifi/hostapd(/.*)?   u:object_r:hostapd_socket:s0
 /data/misc/zoneinfo(/.*)?       u:object_r:zoneinfo_data_file:s0
 /data/misc/vold(/.*)?           u:object_r:vold_data_file:s0
 /data/misc/perfprofd(/.*)?      u:object_r:perfprofd_data_file:s0
@@ -368,6 +369,7 @@
 /sys/power/wake_unlock -- u:object_r:sysfs_wake_lock:s0
 /sys/kernel/uevent_helper --	u:object_r:usermodehelper:s0
 /sys/module/lowmemorykiller(/.*)? -- u:object_r:sysfs_lowmemorykiller:s0
+/sys/module/wlan/parameters/fwpath u:object_r:sysfs_wlan_fwpath:s0
 
 #############################
 # debugfs files
diff --git a/hostapd.te b/hostapd.te
index 204a0d9eb0156414cc49634057191f34d661d57a..41f429aeb22002af2a4ff94f9e92f070febd5c75 100644
--- a/hostapd.te
+++ b/hostapd.te
@@ -1,27 +1,31 @@
 # userspace wifi access points
-type hostapd, domain, domain_deprecated;
+type hostapd, domain;
 type hostapd_exec, exec_type, file_type;
 
+init_daemon_domain(hostapd)
 net_domain(hostapd)
+allow hostapd self:capability { net_admin net_raw };
 
-allow hostapd self:capability { net_admin net_raw setuid setgid };
+# hostapd learns about its network interface via sysfs.
+allow hostapd sysfs:file r_file_perms;
+# hostapd follows the /sys/class/net/wlan0 link to the PCI device.
+allow hostapd sysfs:lnk_file r_file_perms;
+
+# Allow hostapd to access /proc/net/psched
+allow hostapd proc_net:file { getattr open read };
+
+# Various socket permissions.
 allow hostapd self:netlink_socket create_socket_perms;
 allow hostapd self:netlink_generic_socket create_socket_perms;
 allow hostapd self:packet_socket create_socket_perms;
 allow hostapd self:netlink_route_socket nlmsg_write;
 
+# hostapd can read and write WiFi related data and configuration.
+# For example, the entropy file is periodically updated.
 allow hostapd wifi_data_file:file rw_file_perms;
-allow hostapd wifi_data_file:dir create_dir_perms;
-type_transition hostapd wifi_data_file:dir wpa_socket "sockets";
-type_transition hostapd wifi_data_file:dir wpa_socket "hostapd";
-allow hostapd wpa_socket:dir create_dir_perms;
-allow hostapd wpa_socket:sock_file create_file_perms;
-allow hostapd netd:fd use;
-allow hostapd netd:udp_socket { read write };
-allow hostapd netd:fifo_file { read write };
-# TODO: Investigate whether these inherited sockets should be closed on exec.
-allow hostapd netd:netlink_kobject_uevent_socket { read write };
-allow hostapd netd:netlink_nflog_socket { read write };
-allow hostapd netd:netlink_route_socket { read write };
-allow hostapd netd:unix_stream_socket { read write };
-allow hostapd netd:unix_dgram_socket { read write };
+r_dir_file(hostapd, wifi_data_file)
+
+# hostapd wants to create the directory holding its control socket.
+allow hostapd hostapd_socket:dir create_dir_perms;
+# hostapd needs to create, bind to, read, and write its control socket.
+allow hostapd hostapd_socket:sock_file create_file_perms;
diff --git a/netd.te b/netd.te
index 9b44e4bdfe192d19b871dc050b013d74947479f9..5379ac1d79815bbac67d38643f0314b211a6a3a4 100644
--- a/netd.te
+++ b/netd.te
@@ -28,10 +28,14 @@ allow netd devpts:chr_file rw_file_perms;
 # For /proc/sys/net/ipv[46]/route/flush.
 allow netd proc_net:file write;
 
-# For /sys/modules/bcmdhd/parameters/firmware_path
-# XXX Split into its own type.
+# Enables PppController and interface enumeration (among others)
+r_dir_file(netd, sysfs_type)
+# Allows setting interface MTU
 allow netd sysfs:file write;
 
+# For /sys/modules/bcmdhd/parameters/firmware_path
+allow netd sysfs_wlan_fwpath:file w_file_perms;
+
 # TODO: added to match above sysfs rule. Remove me?
 allow netd sysfs_usb:file write;
 
@@ -46,10 +50,6 @@ allow netd wifi_data_file:dir rw_dir_perms;
 allow netd net_data_file:file create_file_perms;
 allow netd net_data_file:dir rw_dir_perms;
 
-# Allow netd to spawn hostapd in it's own domain
-domain_auto_trans(netd, hostapd_exec, hostapd)
-allow netd hostapd:process signal;
-
 # Allow netd to spawn dnsmasq in it's own domain
 domain_auto_trans(netd, dnsmasq_exec, dnsmasq)
 allow netd dnsmasq:process signal;
@@ -76,6 +76,8 @@ allow netd dns_listener_service:service_manager find;
 allow netd netdomain:{tcp_socket udp_socket rawip_socket dccp_socket tun_socket} {read write getattr setattr getopt setopt};
 allow netd netdomain:fd use;
 
+# Allow netd to start and stop hostapd via ctl.start/stop
+set_prop(netd, ctl_default_prop)
 
 ###
 ### Neverallow rules
diff --git a/property.te b/property.te
index 5075e29f7fb19e1567872a8d72cb94d7f053c4fd..90c2912083d05272ec5d161bb8aa9af5061a41b0 100644
--- a/property.te
+++ b/property.te
@@ -13,6 +13,7 @@ type system_radio_prop, property_type, core_property_type;
 type system_prop, property_type, core_property_type;
 type vold_prop, property_type, core_property_type;
 type wifi_log_prop, property_type, log_property_type;
+type wifi_prop, property_type;
 type ctl_bootanim_prop, property_type;
 type ctl_default_prop, property_type;
 type ctl_dumpstate_prop, property_type;
diff --git a/property_contexts b/property_contexts
index cd4068efe60bcc4d8f7f130229fb47701d237cfb..91908312b59a76a56cc71e416e79657ec3c59860 100644
--- a/property_contexts
+++ b/property_contexts
@@ -24,7 +24,6 @@ sys.                    u:object_r:system_prop:s0
 sys.powerctl            u:object_r:powerctl_prop:s0
 sys.usb.ffs.            u:object_r:ffs_prop:s0
 service.                u:object_r:system_prop:s0
-wlan.                   u:object_r:system_prop:s0
 dhcp.                   u:object_r:dhcp_prop:s0
 dhcp.bt-pan.result      u:object_r:pan_result_prop:s0
 bluetooth.              u:object_r:bluetooth_prop:s0
@@ -95,3 +94,6 @@ config.                 u:object_r:config_prop:s0
 ro.config.              u:object_r:config_prop:s0
 dalvik.                 u:object_r:dalvik_prop:s0
 ro.dalvik.              u:object_r:dalvik_prop:s0
+
+# Shared between system server and wificond
+wlan.                   u:object_r:wifi_prop:s0
diff --git a/service.te b/service.te
index 6b5838c5b685f0b15161439a248f89f63b3fff02..d72d6552ac7d1a64ccfad98179bbbb3303a49858 100644
--- a/service.te
+++ b/service.te
@@ -118,4 +118,6 @@ type webviewupdate_service, app_api_service, system_server_service, service_mana
 type wifip2p_service, app_api_service, system_server_service, service_manager_type;
 type wifiscanner_service, system_api_service, system_server_service, service_manager_type;
 type wifi_service, app_api_service, system_server_service, service_manager_type;
+type wificond_service, system_server_service, service_manager_type;
 type window_service, system_api_service, system_server_service, service_manager_type;
+type wpa_supplicant_service, system_server_service, service_manager_type;
diff --git a/service_contexts b/service_contexts
index 0ddbdc17136b70a57cdec7935051f148fcefbb62..2b7a1b113baea63ca315f8498b3cb128bcf6d1e8 100644
--- a/service_contexts
+++ b/service_contexts
@@ -143,5 +143,7 @@ webviewupdate                             u:object_r:webviewupdate_service:s0
 wifip2p                                   u:object_r:wifip2p_service:s0
 wifiscanner                               u:object_r:wifiscanner_service:s0
 wifi                                      u:object_r:wifi_service:s0
+wificond                                  u:object_r:wificond_service:s0
 window                                    u:object_r:window_service:s0
+wpa                                       u:object_r:wpa_supplicant_service:s0
 *                                         u:object_r:default_android_service:s0
diff --git a/system_server.te b/system_server.te
index 88814ec5b6869e27cd181ab48a2e7a2573975f08..a2be42163a2335151611111c00dafa5a6a1923d1 100644
--- a/system_server.te
+++ b/system_server.te
@@ -150,6 +150,7 @@ binder_call(system_server, fingerprintd)
 binder_call(system_server, { appdomain autoplay_app })
 binder_call(system_server, dumpstate)
 binder_call(system_server, netd)
+binder_call(system_server, wificond)
 binder_service(system_server)
 
 # Ask debuggerd to dump backtraces for native stacks of interest.
@@ -341,6 +342,7 @@ set_prop(system_server, debug_prop)
 set_prop(system_server, powerctl_prop)
 set_prop(system_server, fingerprint_prop)
 set_prop(system_server, device_logging_prop)
+set_prop(system_server, wifi_prop)
 userdebug_or_eng(`set_prop(system_server, wifi_log_prop)')
 
 # ctl interface
diff --git a/wificond.te b/wificond.te
new file mode 100644
index 0000000000000000000000000000000000000000..764b69f335cdbed6266ce79fd75d3332799cd925
--- /dev/null
+++ b/wificond.te
@@ -0,0 +1,42 @@
+# wificond
+type wificond, domain;
+type wificond_exec, exec_type, file_type;
+
+init_daemon_domain(wificond)
+
+binder_use(wificond)
+binder_call(wificond, system_server)
+binder_call(wificond, wpa)
+
+allow wificond wificond_service:service_manager { add find };
+
+# wificond writes firmware paths to this file.
+# wificond also changes the owership of this file on startup.
+allow wificond sysfs_wlan_fwpath:file { w_file_perms setattr };
+
+set_prop(wificond, wifi_prop)
+set_prop(wificond, ctl_default_prop)
+
+# create sockets to set interfaces up and down
+allow wificond self:udp_socket create_socket_perms;
+# setting interface state up/down is a privileged ioctl
+allowxperm wificond self:udp_socket ioctl { SIOCSIFFLAGS };
+allow wificond self:capability { net_admin net_raw };
+# allow wificond to speak to nl80211 in the kernel
+allow wificond self:netlink_socket create_socket_perms;
+
+r_dir_file(wificond, proc_net)
+
+# wificond writes out configuration files for wpa_supplicant/hostapd.
+# wificond also reads pid files out of this directory
+allow wificond wifi_data_file:dir rw_dir_perms;
+allow wificond wifi_data_file:file create_file_perms;
+
+# wificond drops root shortly after starting
+# wificond changes the ownership of some files before dropping root
+allow wificond self:capability { setuid setgid setpcap chown };
+
+# wificond cleans up sockets created by wpa_supplicant and framework
+allow wificond wpa_socket:dir rw_dir_perms;
+allow wificond system_wpa_socket:sock_file unlink;
+allow wificond wpa_socket:sock_file unlink;
diff --git a/wpa.te b/wpa.te
index 46d975b8ac48abf723aeceaf4d42a1bb6c3bc712..a49e041e30e1ead534a39aecdf98ba33a372264b 100644
--- a/wpa.te
+++ b/wpa.te
@@ -17,7 +17,10 @@ allow wpa wifi_data_file:dir create_dir_perms;
 allow wpa wifi_data_file:file create_file_perms;
 unix_socket_send(wpa, system_wpa, system_server)
 
+# Binder interface exposed by WPA.
 binder_use(wpa)
+binder_call(wpa, wificond)
+allow wpa wpa_supplicant_service:service_manager { add find };
 
 # Create a socket for receiving info from wpa
 type_transition wpa wifi_data_file:dir wpa_socket "sockets";