diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 5ce7ce7..b6cc3e33 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3624,9 +3624,14 @@ enum ieee80211_reconfig_type {
  * @get_ftm_responder_stats: Retrieve FTM responder statistics, if available.
  *	Statistics should be cumulative, currently no way to reset is provided.
  *
- * @set_noack_tid_bitmap: Set NoAck policy TID bitmap for a virtual interface.
- *	Drivers mplementing this callback must take care of setting NoAck policy
- *	in QOS control field based on the configured TID bitmap.
+ * @set_noack_tid_bitmap: Set NoAck policy TID bitmap. Apply the TID NoAck
+ *	configuration for a particular station when @sta is non-NULL. NoAck
+ *	policy is set to default for a peer when noack_map is -1 for the peer.
+ *	The default NoAck policy for a peer is using netdev NoAck policy.
+ *	When @sta is NULL, apply TID NoAck configuration at virtual interface
+ *	level. Drivers mplementing this callback must take care of setting NoAck
+ *	policy in QOS control field based on the configured TID bitmap.
+ *	This callback may sleep.
  */
 struct ieee80211_ops {
 	void (*tx)(struct ieee80211_hw *hw,
@@ -3917,7 +3922,8 @@ struct ieee80211_ops {
 				       struct cfg80211_ftm_responder_stats *ftm_stats);
 
 	int (*set_noack_tid_bitmap)(struct ieee80211_hw *hw,
-				    struct ieee80211_vif *vif, int noack_map);
+				    struct ieee80211_vif *vif,
+				    struct ieee80211_sta *sta, int noack_map);
 };
 
 /**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 7a7e423..02e6d49 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -344,18 +344,51 @@ static int ieee80211_set_noack_map(struct wiphy *wiphy,
 				  int noack_map)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct sta_info *sta;
+	int ret;
 
-	sdata->noack_map = noack_map;
+	if (!peer) {
+		sdata->noack_map = noack_map;
 
-	if (!sdata->local->ops->set_noack_tid_bitmap) {
-		ieee80211_check_fast_xmit_iface(sdata);
-		return 0;
+		if (!sdata->local->ops->set_noack_tid_bitmap) {
+			ieee80211_check_fast_xmit_iface(sdata);
+			return 0;
+		}
+
+		if (!ieee80211_sdata_running(sdata))
+			return 0;
+
+		return drv_set_noack_tid_bitmap(sdata->local, sdata, NULL,
+						noack_map);
 	}
 
+	/* NoAck policy is for a connected client on the dev */
+
 	if (!ieee80211_sdata_running(sdata))
+		return -ENETDOWN;
+
+	mutex_lock(&sdata->local->sta_mtx);
+
+	sta = sta_info_get_bss(sdata, peer);
+	if (!sta) {
+		mutex_unlock(&sdata->local->sta_mtx);
+		return -ENOENT;
+	}
+
+	sta->noack_map = noack_map;
+
+	if (!sdata->local->ops->set_noack_tid_bitmap) {
+		ieee80211_check_fast_xmit(sta);
+		mutex_unlock(&sdata->local->sta_mtx);
 		return 0;
+	}
+
+	ret = drv_set_noack_tid_bitmap(sdata->local, sdata,
+				       &sta->sta, noack_map);
 
-	return drv_set_noack_tid_bitmap(sdata->local, sdata, noack_map);
+	mutex_unlock(&sdata->local->sta_mtx);
+
+	return ret;
 }
 
 static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index d705938..ed9bd59 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1280,6 +1280,7 @@ static inline void drv_del_nan_func(struct ieee80211_local *local,
 
 static inline int drv_set_noack_tid_bitmap(struct ieee80211_local *local,
 					   struct ieee80211_sub_if_data *sdata,
+					   struct ieee80211_sta *sta,
 					   int noack_map)
 {
 	int ret;
@@ -1293,7 +1294,7 @@ static inline int drv_set_noack_tid_bitmap(struct ieee80211_local *local,
 
 	trace_drv_set_noack_tid_bitmap(local, sdata, noack_map);
 	ret = local->ops->set_noack_tid_bitmap(&local->hw, &sdata->vif,
-					       noack_map);
+					       sta, noack_map);
 	trace_drv_return_int(local, ret);
 
 	return ret;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 06106f2..4999977 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -635,7 +635,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
 				goto err_del_interface;
 
 			if (sdata->noack_map)
-				drv_set_noack_tid_bitmap(local, sdata,
+				drv_set_noack_tid_bitmap(local, sdata, NULL,
 							 sdata->noack_map);
 		}
 
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index fb8c225..d2ea8ee 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -606,6 +606,8 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
 	cfg80211_new_sta(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL);
 	kfree(sinfo);
 
+	sta->noack_map = -1;
+
 	sta_dbg(sdata, "Inserted STA %pM\n", sta->sta.addr);
 
 	/* move reference to rcu-protected */
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 9a04327..863601a 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -583,6 +583,9 @@ struct sta_info {
 
 	struct cfg80211_chan_def tdls_chandef;
 
+	/* TID bitmap for station's NoAck policy */
+	int noack_map;
+
 	/* keep last! */
 	struct ieee80211_sta sta;
 };
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index d744c4b..b57cd1f 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2872,7 +2872,9 @@ void ieee80211_check_fast_xmit(struct sta_info *sta)
 	    test_sta_flag(sta, WLAN_STA_CLEAR_PS_FILT))
 		goto out;
 
-	if (sdata->noack_map && !local->ops->set_noack_tid_bitmap)
+	if (((sta->noack_map == -1 && sdata->noack_map) ||
+	     (sta->noack_map != -1 && sta->noack_map)) &&
+	    !local->ops->set_noack_tid_bitmap)
 		goto out;
 
 	/* fast-xmit doesn't handle fragmentation at all */
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 11c14b9..b1722b8 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -227,6 +227,38 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
 }
 
 /**
+ * ieee80211_get_noack_map - Get TID bitmap of NoAck policy. NoAck policy
+ * could be device wide or per-station.
+ *
+ * @sdata: local subif
+ * @mac: MAC address of the receiver
+ */
+int ieee80211_get_noack_map(struct ieee80211_sub_if_data *sdata, const u8 *mac)
+{
+	struct sta_info *sta;
+	int noack_map = 0;
+
+	/* Retrieve per-station noack_map config for the receiver, if any */
+
+	rcu_read_lock();
+
+	sta = sta_info_get(sdata, mac);
+	if (!sta) {
+		rcu_read_unlock();
+		return noack_map;
+	}
+
+	noack_map = sta->noack_map;
+
+	rcu_read_unlock();
+
+	if (noack_map == -1)
+		noack_map = sdata->noack_map;
+
+	return noack_map;
+}
+
+/**
  * ieee80211_set_qos_hdr - Fill in the QoS header if there is one.
  *
  * @sdata: local subif
@@ -257,7 +289,7 @@ void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
 
 	if (is_multicast_ether_addr(hdr->addr1) ||
 	    (!sdata->local->ops->set_noack_tid_bitmap &&
-	    sdata->noack_map & BIT(tid))) {
+	     ieee80211_get_noack_map(sdata, hdr->addr1) & BIT(tid))) {
 		flags |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK;
 		info->flags |= IEEE80211_TX_CTL_NO_ACK;
 	}
