diff --git a/src/dpp.c b/src/dpp.c
index 004b431d..f7989d2b 100644
--- a/src/dpp.c
+++ b/src/dpp.c
@@ -66,7 +66,6 @@ static struct l_genl_family *nl80211;
 static uint8_t broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 static struct l_queue *dpp_list;
 static uint32_t mlme_watch;
-static uint32_t unicast_watch;
 
 static uint8_t dpp_prefix[] = { 0x04, 0x09, 0x50, 0x6f, 0x9a, 0x1a, 0x01 };
 
@@ -552,6 +551,8 @@ static void dpp_reset(struct dpp_sm *dpp)
 
 	dpp_property_changed_notify(dpp);
 
+	frame_watch_group_remove(dpp->wdev_id, FRAME_GROUP_DPP);
+
 	dpp->interface = DPP_INTERFACE_UNBOUND;
 
 	if (station) {
@@ -3475,10 +3476,11 @@ failed:
 	dpp_reset(dpp);
 }
 
-static void dpp_handle_frame(struct dpp_sm *dpp,
-				const struct mmpdu_header *frame,
-				const void *body, size_t body_len)
+static void dpp_handle_frame(const struct mmpdu_header *frame,
+				const void *body, size_t body_len,
+				int rssi, void *user_data)
 {
+	struct dpp_sm *dpp = user_data;
 	const uint8_t *ptr;
 
 	/*
@@ -3638,99 +3640,6 @@ retransmit:
 						dpp_frame_timeout, dpp, NULL);
 }
 
-static void dpp_unicast_notify(struct l_genl_msg *msg, void *user_data)
-{
-	struct dpp_sm *dpp;
-	const uint64_t *wdev_id = NULL;
-	struct l_genl_attr attr;
-	uint16_t type, len, frame_len;
-	const void *data;
-	const struct mmpdu_header *mpdu = NULL;
-	const uint8_t *body;
-	size_t body_len;
-
-	if (l_genl_msg_get_command(msg) != NL80211_CMD_FRAME)
-		return;
-
-	if (!l_genl_attr_init(&attr, msg))
-		return;
-
-	while (l_genl_attr_next(&attr, &type, &len, &data)) {
-		switch (type) {
-		case NL80211_ATTR_WDEV:
-			if (len != 8)
-				break;
-
-			wdev_id = data;
-			break;
-
-		case NL80211_ATTR_FRAME:
-			mpdu = mpdu_validate(data, len);
-			if (!mpdu) {
-				l_warn("Frame didn't validate as MMPDU");
-				return;
-			}
-
-			frame_len = len;
-			break;
-		}
-	}
-
-	if (!wdev_id) {
-		l_warn("Bad wdev attribute");
-		return;
-	}
-
-	dpp = l_queue_find(dpp_list, match_wdev, wdev_id);
-	if (!dpp)
-		return;
-
-	if (!mpdu) {
-		l_warn("Missing frame data");
-		return;
-	}
-
-	body = mmpdu_body(mpdu);
-	body_len = (const uint8_t *) mpdu + frame_len - body;
-
-	if (body_len < sizeof(dpp_prefix) ||
-			memcmp(body, dpp_prefix, sizeof(dpp_prefix)) != 0)
-		return;
-
-	dpp_handle_frame(dpp, mpdu, body, body_len);
-}
-
-static void dpp_frame_watch_cb(struct l_genl_msg *msg, void *user_data)
-{
-	if (l_genl_msg_get_error(msg) < 0)
-		l_error("Could not register frame watch type %04x: %i",
-			L_PTR_TO_UINT(user_data), l_genl_msg_get_error(msg));
-}
-
-/*
- * Special case the frame watch which includes the presence frames since they
- * require multicast support. This is only supported by ath9k, so adding
- * general support to frame-xchg isn't desireable.
- */
-static void dpp_frame_watch(struct dpp_sm *dpp, uint16_t frame_type,
-				const uint8_t *prefix, size_t prefix_len)
-{
-	struct l_genl_msg *msg;
-
-	msg = l_genl_msg_new_sized(NL80211_CMD_REGISTER_FRAME, 32 + prefix_len);
-
-	l_genl_msg_append_attr(msg, NL80211_ATTR_WDEV, 8, &dpp->wdev_id);
-	l_genl_msg_append_attr(msg, NL80211_ATTR_FRAME_TYPE, 2, &frame_type);
-	l_genl_msg_append_attr(msg, NL80211_ATTR_FRAME_MATCH,
-				prefix_len, prefix);
-	if (dpp->mcast_support)
-		l_genl_msg_append_attr(msg, NL80211_ATTR_RECEIVE_MULTICAST,
-					0, NULL);
-
-	l_genl_family_send(nl80211, msg, dpp_frame_watch_cb,
-					L_UINT_TO_PTR(frame_type), NULL);
-}
-
 static void dpp_start_enrollee(struct dpp_sm *dpp);
 static bool dpp_start_pkex_enrollee(struct dpp_sm *dpp);
 
@@ -3820,8 +3729,6 @@ static void dpp_create(struct netdev *netdev)
 {
 	struct l_dbus *dbus = dbus_get_bus();
 	struct dpp_sm *dpp = l_new(struct dpp_sm, 1);
-	uint8_t dpp_conf_response_prefix[] = { 0x04, 0x0b };
-	uint8_t dpp_conf_request_prefix[] = { 0x04, 0x0a };
 	uint64_t wdev_id = netdev_get_wdev_id(netdev);
 
 	dpp->netdev = netdev;
@@ -3857,17 +3764,6 @@ static void dpp_create(struct netdev *netdev)
 	 */
 	dpp->refcount = 2;
 
-	dpp_frame_watch(dpp, 0x00d0, dpp_prefix, sizeof(dpp_prefix));
-
-	frame_watch_add(netdev_get_wdev_id(netdev), 0, 0x00d0,
-				dpp_conf_response_prefix,
-				sizeof(dpp_conf_response_prefix), false,
-				dpp_handle_config_response_frame, dpp, NULL);
-	frame_watch_add(netdev_get_wdev_id(netdev), 0, 0x00d0,
-				dpp_conf_request_prefix,
-				sizeof(dpp_conf_request_prefix), false,
-				dpp_handle_config_request_frame, dpp, NULL);
-
 	dpp->known_network_watch = known_networks_watch_add(
 					dpp_known_network_watch, dpp, NULL);
 
@@ -4012,6 +3908,26 @@ done:
 	return 0;
 }
 
+static void dpp_add_frame_watches(struct dpp_sm *dpp, bool multicast_rx)
+{
+	uint8_t dpp_conf_response_prefix[] = { 0x04, 0x0b };
+	uint8_t dpp_conf_request_prefix[] = { 0x04, 0x0a };
+
+	frame_watch_add(dpp->wdev_id, FRAME_GROUP_DPP, 0x00d0,
+			dpp_prefix, sizeof(dpp_prefix), multicast_rx,
+			dpp_handle_frame, dpp, NULL);
+
+	frame_watch_add(dpp->wdev_id, FRAME_GROUP_DPP, 0x00d0,
+			dpp_conf_response_prefix,
+			sizeof(dpp_conf_response_prefix), false,
+			dpp_handle_config_response_frame, dpp, NULL);
+
+	frame_watch_add(dpp->wdev_id, FRAME_GROUP_DPP, 0x00d0,
+			dpp_conf_request_prefix,
+			sizeof(dpp_conf_request_prefix), false,
+			dpp_handle_config_request_frame, dpp, NULL);
+}
+
 static void dpp_start_enrollee(struct dpp_sm *dpp)
 {
 	uint32_t freq = band_channel_to_freq(6, BAND_FREQ_2_4_GHZ);
@@ -4051,6 +3967,8 @@ static struct l_dbus_message *dpp_dbus_start_enrollee(struct l_dbus *dbus,
 	dpp->role = DPP_CAPABILITY_ENROLLEE;
 	dpp->interface = DPP_INTERFACE_DPP;
 
+	dpp_add_frame_watches(dpp, false);
+
 	ret = dpp_try_disconnect_station(dpp, &wait_for_disconnect);
 	if (ret < 0) {
 		dpp_reset(dpp);
@@ -4188,6 +4106,8 @@ static struct l_dbus_message *dpp_start_configurator_common(
 	} else
 		dpp->current_freq = bss->frequency;
 
+	dpp_add_frame_watches(dpp, responder);
+
 	dpp->uri = dpp_generate_uri(dpp->own_asn1, dpp->own_asn1_len, 2,
 					netdev_get_address(dpp->netdev),
 					&bss->frequency, 1, NULL, NULL);
@@ -4517,6 +4437,8 @@ static struct l_dbus_message *dpp_dbus_pkex_start_enrollee(struct l_dbus *dbus,
 	dpp->state = DPP_STATE_PKEX_EXCHANGE;
 	dpp->interface = DPP_INTERFACE_PKEX;
 
+	dpp_add_frame_watches(dpp, false);
+
 	ret = dpp_try_disconnect_station(dpp, &wait_for_disconnect);
 	if (ret < 0) {
 		dpp_reset(dpp);
@@ -4613,6 +4535,7 @@ static struct l_dbus_message *dpp_start_pkex_configurator(struct dpp_sm *dpp,
 	dpp->config = dpp_configuration_new(network_get_settings(network),
 						network_get_ssid(network),
 						hs->akm_suite);
+	dpp_add_frame_watches(dpp, true);
 
 	dpp_reset_protocol_timer(dpp, DPP_PKEX_PROTO_TIMEOUT);
 	dpp_property_changed_notify(dpp);
@@ -4741,11 +4664,6 @@ static int dpp_init(void)
 	mlme_watch = l_genl_family_register(nl80211, "mlme", dpp_mlme_notify,
 						NULL, NULL);
 
-	unicast_watch = l_genl_add_unicast_watch(iwd_get_genl(),
-						NL80211_GENL_NAME,
-						dpp_unicast_notify,
-						NULL, NULL);
-
 	dpp_list = l_queue_new();
 
 	return 0;
@@ -4760,8 +4678,6 @@ static void dpp_exit(void)
 
 	netdev_watch_remove(netdev_watch);
 
-	l_genl_remove_unicast_watch(iwd_get_genl(), unicast_watch);
-
 	l_genl_family_unregister(nl80211, mlme_watch);
 	mlme_watch = 0;
 
