diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 84e74eef0..cea75b85e 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -229,9 +229,6 @@ static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
 {
        int pri_chan, sec_chan;

-       if (!iface->conf->secondary_channel)
-               return 1; /* HT40 not used */
-
        pri_chan = iface->conf->channel;
        sec_chan = pri_chan + iface->conf->secondary_channel * 4;

@@ -692,31 +689,30 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
        return 0;
 }

-
 static int hostapd_is_usable_chan(struct hostapd_iface *iface,
                                  int channel, int primary)
 {
-       int i;
        struct hostapd_channel_data *chan;

        if (!iface->current_mode)
                return 0;

-       for (i = 0; i < iface->current_mode->num_channels; i++) {
-               chan = &iface->current_mode->channels[i];
-               if (chan->chan != channel)
-                       continue;
+       chan = hw_get_channel_chan(iface->current_mode, channel, NULL);
+       if (!chan)
+               return 0;

-               if (!(chan->flag & HOSTAPD_CHAN_DISABLED))
-                       return 1;
+       if (primary && chan_pri_allowed(chan))
+               return 1;

-               wpa_printf(MSG_DEBUG,
-                          "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s",
-                          primary ? "" : "Configured HT40 secondary ",
-                          i, chan->chan, chan->flag,
-                          chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
-                          chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
-       }
+       if (!(chan->flag & HOSTAPD_CHAN_DISABLED))
+               return 1;
+
+       wpa_printf(MSG_DEBUG,
+                  "%schannel (%i) is disabled for use in AP mode, flags: 0x%x%s%s",
+                  primary ? "" : "Configured HT40 secondary ",
+                  chan->chan, chan->flag,
+                  chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
+                  chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");

        wpa_printf(MSG_INFO, "Channel %d (%s) not allowed for AP mode",
                   channel, primary ? "primary" : "secondary");
@@ -727,6 +723,13 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface,
 static int hostapd_is_usable_chans(struct hostapd_iface *iface)
 {
        int secondary_chan;
+       struct hostapd_channel_data *pri_chan;
+
+       pri_chan = hw_get_channel_chan(iface->current_mode,
+                                      iface->conf->channel, NULL);
+
+       if (!pri_chan)
+               return 0;

        if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1))
                return 0;
@@ -741,13 +744,15 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)

        /* Both HT40+ and HT40- are set, pick a valid secondary channel */
        secondary_chan = iface->conf->channel + 4;
-       if (hostapd_is_usable_chan(iface, secondary_chan, 0)) {
+       if (hostapd_is_usable_chan(iface, secondary_chan, 0) &&
+           (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) {
                iface->conf->secondary_channel = 1;
                return 1;
        }

        secondary_chan = iface->conf->channel - 4;
-       if (hostapd_is_usable_chan(iface, secondary_chan, 0)) {
+       if (hostapd_is_usable_chan(iface, secondary_chan, 0) &&
+           (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) {
                iface->conf->secondary_channel = -1;
                return 1;
        }
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index db4037927..903c17742 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -84,35 +84,45 @@ int hw_get_chan(struct hostapd_hw_modes *mode, int freq)
 }


-int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
-                             int sec_chan)
+int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan_num,
+                             int sec_chan_num)
 {
-       int ok, j, first;
+       int ok, first;
        int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
                          149, 157, 165, 184, 192 };
        size_t k;
+       struct hostapd_channel_data *pri_chan, *sec_chan;
+       const int ht_plus = pri_chan_num < sec_chan_num ? 1 : 0;

-       if (pri_chan == sec_chan || !sec_chan)
-               return 1; /* HT40 not used */
+       pri_chan = hw_get_channel_chan(mode, pri_chan_num, NULL);
+       if (!pri_chan)
+               return 0;
+
+       if (pri_chan_num == sec_chan_num || !sec_chan_num) {
+               if (chan_pri_allowed(pri_chan)) {
+                       return 1; /* HT40 not used */
+               } else {
+                       wpa_printf(MSG_ERROR, "Channel %d is not allowed as primary",
+                                  pri_chan_num);
+                       return 0;
+               }
+       }
+
+       sec_chan = hw_get_channel_chan(mode, sec_chan_num, NULL);
+       if (!sec_chan)
+               return 0;

        wpa_printf(MSG_DEBUG,
                   "HT40: control channel: %d  secondary channel: %d",
-                  pri_chan, sec_chan);
+                  pri_chan_num, sec_chan_num);

        /* Verify that HT40 secondary channel is an allowed 20 MHz
         * channel */
-       ok = 0;
-       for (j = 0; j < mode->num_channels; j++) {
-               struct hostapd_channel_data *chan = &mode->channels[j];
-               if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
-                   chan->chan == sec_chan) {
-                       ok = 1;
-                       break;
-               }
-       }
-       if (!ok) {
+       if ((sec_chan->flag & HOSTAPD_CHAN_DISABLED) ||
+           (ht_plus && !(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) ||
+           (!ht_plus && !(pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M))) {
                wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
-                          sec_chan);
+                          sec_chan_num);
                return 0;
        }

@@ -125,7 +135,7 @@ int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
        if (mode->mode != HOSTAPD_MODE_IEEE80211A)
                return 1;

-       first = pri_chan < sec_chan ? pri_chan : sec_chan;
+       first = pri_chan_num < sec_chan_num ? pri_chan_num : sec_chan_num;

        ok = 0;
        for (k = 0; k < ARRAY_SIZE(allowed); k++) {
@@ -136,7 +146,7 @@ int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
        }
        if (!ok) {
                wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
-                          pri_chan, sec_chan);
+                          pri_chan_num, sec_chan_num);
                return 0;
        }

@@ -553,3 +563,54 @@ int ieee80211ac_cap_check(u32 hw, u32 conf)
 }

 #endif /* CONFIG_IEEE80211AC */
+
+u32 num_chan_to_bw(int num_chans)
+{
+       switch (num_chans) {
+       case 2:
+       case 4:
+       case 8:
+               return num_chans * 20;
+       default:
+               return 20;
+       }
+}
+
+int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
+                   int ht40_plus, int pri)
+{
+       u32 bw_mask;
+
+       switch (bw) {
+       case 20:
+               bw_mask = HOSTAPD_CHAN_WIDTH_20;
+               break;
+       case 40:
+               /* HT 40 MHz support declared only for primary channel,
+                * just skip 40 MHz secondary checking */
+               if (pri && ht40_plus)
+                       bw_mask = HOSTAPD_CHAN_WIDTH_40P;
+               else if (pri && !ht40_plus)
+                       bw_mask = HOSTAPD_CHAN_WIDTH_40M;
+               else
+                       bw_mask = 0;
+               break;
+       case 80:
+               bw_mask = HOSTAPD_CHAN_WIDTH_80;
+               break;
+       case 160:
+               bw_mask = HOSTAPD_CHAN_WIDTH_160;
+               break;
+       default:
+               bw_mask = 0;
+               break;
+       }
+
+       return (chan->allowed_bw & bw_mask) == bw_mask;
+}
+
+int chan_pri_allowed(const struct hostapd_channel_data *chan)
+{
+       return !(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+               (chan->allowed_bw & HOSTAPD_CHAN_WIDTH_20);
+}
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index 9cddbd50e..b2ae50488 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -20,8 +20,8 @@ struct hostapd_channel_data * hw_get_channel_freq(struct hostapd_hw_modes *mode,
 int hw_get_freq(struct hostapd_hw_modes *mode, int chan);
 int hw_get_chan(struct hostapd_hw_modes *mode, int freq);

-int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
-                             int sec_chan);
+int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan_num,
+                             int sec_chan_num);
 void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan);
 int check_40mhz_5g(struct hostapd_hw_modes *mode,
                   struct wpa_scan_results *scan_res, int pri_chan,
@@ -39,4 +39,11 @@ void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps,
                      int disabled);
 int ieee80211ac_cap_check(u32 hw, u32 conf);

+u32 num_chan_to_bw(int num_chans);
+/* check if BW is applicable for channel */
+int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
+                   int ht40_plus, int pri);
+/* check if channel is allowed to be used as primary */
+int chan_pri_allowed(const struct hostapd_channel_data *chan);
+
 #endif /* HW_FEATURES_COMMON_H */
