diff --git a/README.md b/README.md
index 8bf3ac20c430826bd2d6bd0958fb075fd433cf6b..a10bb47f15e3117c5f323768b6aa5d0f81c501fc 100644
--- a/README.md
+++ b/README.md
@@ -161,6 +161,7 @@ Next change the version in the following places:
 
 # Release Notes
 
+* 0.38.4 Fixed ordering in subband_frequency_R, which broke frequency calculations for HBA
 * 0.38.3 Upgraded to JupyterLab v4
 * 0.38.2 Fixed polling of some attributes required by Metadata device
          Wait 2s after enabling FPGA_processing_enable_RW to allow it to propagate
diff --git a/tangostationcontrol/VERSION b/tangostationcontrol/VERSION
index f2687f32e8878bb36f76e6cb14a4b09169e25f8b..87f0b954e35439a92505a3e2a24a345ba3c0ba98 100644
--- a/tangostationcontrol/VERSION
+++ b/tangostationcontrol/VERSION
@@ -1 +1 @@
-0.38.3
+0.38.4
diff --git a/tangostationcontrol/integration_test/default/devices/test_device_digitalbeam.py b/tangostationcontrol/integration_test/default/devices/test_device_digitalbeam.py
index a42bfbb26f245b372bc9c8479364e01fa9401d44..7ae9b05a50ac7e5098c2b41c414e29caee16b098 100644
--- a/tangostationcontrol/integration_test/default/devices/test_device_digitalbeam.py
+++ b/tangostationcontrol/integration_test/default/devices/test_device_digitalbeam.py
@@ -49,8 +49,6 @@ class TestDeviceDigitalBeam(AbstractTestBases.TestDeviceBase):
         """Intentionally recreate the device object in each test"""
         super().setUp("STAT/DigitalBeam/HBA0")
 
-        self.proxy.put_property({"Beamlet_Select": [True] * N_beamlets_ctrl})
-
         self.recv_proxy = self.setup_proxy(self.recv_iden, defaults=True)
         self.sdpfirmware_proxy = self.setup_proxy(self.sdpfirmware_iden, defaults=True)
         self.sdp_proxy = self.setup_proxy(self.sdp_iden)
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py b/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py
index fbfa10e3ea5ead1b9585e8e5e24973e7acff1774..ab2b105e17b363377d2834520e2b5d4edf83e57d 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py
@@ -45,6 +45,7 @@ logger = logging.getLogger()
 
 @device_metrics(
     exclude=[
+        "beamlet_frequency_R",
         "FPGA_beamlet_subband_select_*",
         "FPGA_bf_weights_*",
         "FPGA_beamlet_output_hdr_*",
@@ -607,6 +608,15 @@ class Beamlet(OPCUADevice):
         fisallowed="is_attribute_access_allowed",
     )
 
+    beamlet_frequency_R = attribute(
+        doc="Frequency of each beamlet for each input",
+        unit="Hz",
+        dtype=((numpy.float64,),),
+        max_dim_y=N_pn * A_pn,
+        max_dim_x=N_beamlets_ctrl,
+        fisallowed="is_attribute_access_allowed",
+    )
+
     def get_defaults(self, properties: Dict[str, object]) -> List[Tuple[str, object]]:
         return super().get_defaults(properties) + self._beamlet_output_defaults(
             properties
@@ -712,7 +722,7 @@ class Beamlet(OPCUADevice):
     def cache_clear(self):
         """Explicitly clear any caches."""
 
-        self._beamlet_frequencies.cache_clear()
+        self.beamlet_frequencies.cache_clear()
 
     """
        The SDP FPGAs correct for signal-delay differences by rotating the phases of the antenna signals. A delay
@@ -734,25 +744,10 @@ class Beamlet(OPCUADevice):
        The phases, delays, and final beam weights, all have shape (fpga_nr, [input_nr][pol][beamlet_nr]).
     """
 
-    @lru_cache()  # this function requires large hardware reads for values that don't change often
-    def _beamlet_frequencies(self):
-        """Obtain the frequencies (in Hz) of each subband
-        that is selected for each antenna and beamlet.
-
-        Returns shape (fpga_nr, input_nr, beamlet_nr), so one value per antenna, not per input.
-        This makes the result directly usable for FPGA_bf_weights_pp_RW.
-        """
-
-        # obtain which subband is selected for each input and beamlet
-        beamlet_subbands = self.read_attribute(
-            "FPGA_beamlet_subband_select_RW"
-        ).reshape(
-            N_pn, A_pn, N_pol, N_beamlets_ctrl
-        )  # orig: (fpga_nr, [input_nr][pol][beamlet_nr])
-        subband_frequencies = self.sdp_proxy.subband_frequency_R.reshape(
-            N_pn, A_pn, N_pol, N_subbands
-        )  # orig: ([fpga_nr][input_nr], subband_nr)
-
+    @staticmethod
+    def _beamlet_frequencies(
+        beamlet_subbands: numpy.ndarray, subband_frequencies: numpy.ndarray
+    ) -> numpy.ndarray:
         def frequencies_per_input(fpga_nr, antenna_nr):
             """Return the frequencies for the selected subbands of the given input."""
             return numpy.take(
@@ -768,14 +763,35 @@ class Beamlet(OPCUADevice):
         frequencies = numpy.array(
             [
                 frequencies_per_input(fpga_nr, antenna_nr)
-                for antenna_nr in range(A_pn)
                 for fpga_nr in range(N_pn)
+                for antenna_nr in range(A_pn)
             ],
             dtype=numpy.float64,
         )
 
         return frequencies.reshape(N_pn, A_pn, N_beamlets_ctrl)
 
+    @lru_cache()  # this function requires large hardware reads for values that don't change often
+    def beamlet_frequencies(self):
+        """Obtain the frequencies (in Hz) of each subband
+        that is selected for each antenna and beamlet.
+
+        Returns shape (fpga_nr, input_nr, beamlet_nr), so one value per antenna, not per input.
+        This makes the result directly usable for FPGA_bf_weights_pp_RW.
+        """
+
+        # obtain which subband is selected for each input and beamlet
+        beamlet_subbands = self.read_attribute(
+            "FPGA_beamlet_subband_select_RW"
+        ).reshape(
+            N_pn, A_pn, N_pol, N_beamlets_ctrl
+        )  # orig: (fpga_nr, [input_nr][pol][beamlet_nr])
+        subband_frequencies = self.sdp_proxy.subband_frequency_R.reshape(
+            N_pn, A_pn, N_pol, N_subbands
+        )  # orig: ([fpga_nr][input_nr], subband_nr)
+
+        return self._beamlet_frequencies(beamlet_subbands, subband_frequencies)
+
     @staticmethod
     def _calculate_bf_weights(
         delays: numpy.ndarray, beamlet_frequencies: numpy.ndarray
@@ -795,6 +811,9 @@ class Beamlet(OPCUADevice):
 
         return bf_weights
 
+    def read_beamlet_frequency_R(self):
+        return self.beamlet_frequencies().reshape(N_pn * A_pn, N_beamlets_ctrl)
+
     # --------
     # Commands
     # --------
@@ -805,7 +824,7 @@ class Beamlet(OPCUADevice):
 
         # Calculate the FPGA weight array
         delays = delays.reshape(N_pn, A_pn, N_beamlets_ctrl)
-        beamlet_frequencies = self._beamlet_frequencies()
+        beamlet_frequencies = self.beamlet_frequencies()
         bf_weights = self._calculate_bf_weights(delays, beamlet_frequencies)
 
         return bf_weights.flatten()
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
index 5d56bff41d1bb9d20d5cc9a5fdd5fdf685296fe5..306adef04915eff9cc875acc19b1440fbd90a54e 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
@@ -494,15 +494,10 @@ class SDP(OPCUADevice):
         # to make sure the subbands are ascending in frequency
         self.proxy.FPGA_spectral_inversion_RW = self._nyquist_zone % 2
 
-    @DurationMetric()
-    def read_subband_frequency_R(self):
-        clock = self.control.read_parent_attribute("clock_RW")  # scalar
-        nyquist_zone = numpy.array(
-            self.read_attribute("nyquist_zone_RW")
-        )  # N_pn x S_pn
-        spectral_inversion = self.read_attribute(
-            "FPGA_spectral_inversion_RW"
-        )  # N_pn x S_pn
+    @staticmethod
+    def _subband_frequencies(
+        clock: int, nyquist_zone: numpy.ndarray, spectral_inversion: numpy.ndarray
+    ) -> numpy.ndarray:
         subband_list = numpy.array(range(N_subbands))
 
         def frequencies_per_input(fpga_nr, input_nr):
@@ -518,14 +513,26 @@ class SDP(OPCUADevice):
         frequencies = numpy.array(
             [
                 frequencies_per_input(fpga_nr, input_nr)
-                for input_nr in range(S_pn)
                 for fpga_nr in range(N_pn)
+                for input_nr in range(S_pn)
             ],
             dtype=numpy.float64,
         )
 
         return frequencies.reshape(N_pn * S_pn, N_subbands)
 
+    @DurationMetric()
+    def read_subband_frequency_R(self):
+        clock = self.control.read_parent_attribute("clock_RW")  # scalar
+        nyquist_zone = numpy.array(
+            self.read_attribute("nyquist_zone_RW")
+        )  # N_pn x S_pn
+        spectral_inversion = self.read_attribute(
+            "FPGA_spectral_inversion_RW"
+        )  # N_pn x S_pn
+
+        return self._subband_frequencies(clock, nyquist_zone, spectral_inversion)
+
     # ----------
     # Summarising Attributes
     # ----------
diff --git a/tangostationcontrol/test/devices/sdp/test_beamlet_device.py b/tangostationcontrol/test/devices/sdp/test_beamlet_device.py
index 062113ed123d3e044a0bb115a6824d233d89b43d..0e8ef1a105c09ef2540c1268348b994696323f9f 100644
--- a/tangostationcontrol/test/devices/sdp/test_beamlet_device.py
+++ b/tangostationcontrol/test/devices/sdp/test_beamlet_device.py
@@ -6,8 +6,12 @@ import numpy.testing
 
 from tangostationcontrol.common.constants import (
     CLK_200_MHZ,
+    A_pn,
     N_pn,
+    N_pol,
+    N_beamlets_ctrl,
     N_bdo_destinations_mm,
+    N_subbands,
 )
 from tangostationcontrol.common.sdp import weight_to_complex
 from tangostationcontrol.devices.sdp.beamlet import Beamlet
@@ -145,3 +149,87 @@ class TestBeamletDevice(base.TestCase):
             defaults["FPGA_beamlet_output_multiple_hdr_udp_destination_port_RW"],
             [PORTs + [0] * (N_bdo_destinations_mm - 4)] * N_pn,
         )
+
+    def _verify_beamlet_frequencies(self, beamlet_subbands, subband_frequencies):
+        beamlet_frequencies = Beamlet._beamlet_frequencies(
+            beamlet_subbands, subband_frequencies
+        )
+
+        # explicitly construct expected output. We can count on the subband_frequency
+        # to work as that is tested elsewhere.
+        expected_frequencies = numpy.zeros(
+            (N_pn, A_pn, N_beamlets_ctrl), dtype=numpy.float64
+        )
+        for beamlet_nr in range(N_beamlets_ctrl):
+            for fpga_nr in range(N_pn):
+                for antenna_nr in range(A_pn):
+                    pol_nr = 0
+                    subband_nr = beamlet_subbands[
+                        fpga_nr, antenna_nr, pol_nr, beamlet_nr
+                    ]
+                    expected_frequencies[fpga_nr, antenna_nr, beamlet_nr] = (
+                        subband_frequencies[fpga_nr, antenna_nr, pol_nr, subband_nr]
+                    )
+
+        numpy.testing.assert_array_almost_equal(
+            beamlet_frequencies, expected_frequencies.reshape(beamlet_frequencies.shape)
+        )
+
+    def test_beamlet_frequencies_basic(self):
+        beamlet_subbands = numpy.array(
+            [[[list(range(N_beamlets_ctrl))] * N_pol] * A_pn] * N_pn, dtype=numpy.uint32
+        )
+        subband_indices = numpy.array(
+            [[[list(range(N_subbands))] * N_pol] * A_pn] * N_pn, dtype=numpy.uint32
+        )
+        subband_frequencies = subband_indices * (CLK_200_MHZ / N_subbands)
+
+        self._verify_beamlet_frequencies(beamlet_subbands, subband_frequencies)
+
+    def test_beamlet_frequencies_mixed_fpga_settings(self):
+        """Test different settings for the FPGAs to verify the ordering."""
+
+        beamlet_subbands = numpy.array(
+            [[[list(range(N_beamlets_ctrl))] * N_pol] * A_pn] * N_pn, dtype=numpy.uint32
+        )
+        subband_indices = numpy.array(
+            [[[list(range(N_subbands))] * N_pol] * A_pn] * N_pn, dtype=numpy.uint32
+        )
+        subband_frequencies = subband_indices * (CLK_200_MHZ / N_subbands)
+
+        # change settings for FPGAs beyond 4
+        beamlet_subbands[4:, :, :, :] = 0
+
+        self._verify_beamlet_frequencies(beamlet_subbands, subband_frequencies)
+
+    def test_beamlet_frequencies_mixed_input_settings(self):
+        """Test different settings for the inputs of the FPGAs to verify the ordering."""
+
+        beamlet_subbands = numpy.array(
+            [[[list(range(N_beamlets_ctrl))] * N_pol] * A_pn] * N_pn, dtype=numpy.uint32
+        )
+        subband_indices = numpy.array(
+            [[[list(range(N_subbands))] * N_pol] * A_pn] * N_pn, dtype=numpy.uint32
+        )
+        subband_frequencies = subband_indices * (CLK_200_MHZ / N_subbands)
+
+        # change settings for inputs beyond 4
+        beamlet_subbands[:, 4:, :, :] = 0
+
+        self._verify_beamlet_frequencies(beamlet_subbands, subband_frequencies)
+
+    def test_beamlet_frequencies_unordered_subbands(self):
+        """Test a shuffled order of subbands."""
+
+        beamlet_subbands = numpy.array(
+            [[[list(range(N_beamlets_ctrl))] * N_pol] * A_pn] * N_pn, dtype=numpy.uint32
+        )
+        subband_indices = numpy.array(
+            [[[list(range(N_subbands))] * N_pol] * A_pn] * N_pn, dtype=numpy.uint32
+        )
+
+        # shuffle subbands (assuming 7 is coprime to N_subbands)
+        subband_indices = (subband_indices * 7) % N_subbands
+        subband_frequencies = subband_indices * (CLK_200_MHZ / N_subbands)
+
+        self._verify_beamlet_frequencies(beamlet_subbands, subband_frequencies)
diff --git a/tangostationcontrol/test/devices/sdp/test_sdp_device.py b/tangostationcontrol/test/devices/sdp/test_sdp_device.py
new file mode 100644
index 0000000000000000000000000000000000000000..4b8388cc651ebe9e7ac50c442847b97c765f902a
--- /dev/null
+++ b/tangostationcontrol/test/devices/sdp/test_sdp_device.py
@@ -0,0 +1,84 @@
+# Copyright (C) 2024 ASTRON (Netherlands Institute for Radio Astronomy)
+# SPDX-License-Identifier: Apache-2.0
+
+import numpy
+import numpy.testing
+
+# Internal test imports
+from test.devices import device_base
+
+from tangostationcontrol.common.constants import (
+    CLK_160_MHZ,
+    CLK_200_MHZ,
+    N_pn,
+    S_pn,
+    N_subbands,
+)
+from tangostationcontrol.common.sdp import subband_frequency
+from tangostationcontrol.devices.sdp.sdp import SDP
+
+
+class TestSDPDevice(device_base.DeviceTestCase):
+    def _verify_subband_frequencies(self, clock, nyquist_zone, spectral_inversion):
+        subband_frequencies = SDP._subband_frequencies(
+            clock, nyquist_zone, spectral_inversion
+        )
+
+        # explicitly construct expected output. We can count on the subband_frequency
+        # to work as that is tested elsewhere.
+        expected_frequencies = numpy.zeros(
+            (N_pn, S_pn, N_subbands), dtype=numpy.float64
+        )
+        for sb in range(N_subbands):
+            for fpga_nr in range(N_pn):
+                for antenna_nr in range(S_pn):
+                    expected_frequencies[fpga_nr, antenna_nr, sb] = subband_frequency(
+                        sb,
+                        clock,
+                        nyquist_zone[fpga_nr, antenna_nr],
+                        spectral_inversion[fpga_nr, antenna_nr],
+                    )
+
+        numpy.testing.assert_array_almost_equal(
+            subband_frequencies, expected_frequencies.reshape(subband_frequencies.shape)
+        )
+
+    def test_subband_frequencies_200mhz(self):
+        clock = CLK_200_MHZ
+        nyquist_zone = numpy.array([[1] * S_pn] * N_pn)
+        spectral_inversion = numpy.array([[True] * S_pn] * N_pn)
+
+        self._verify_subband_frequencies(clock, nyquist_zone, spectral_inversion)
+
+    def test_subband_frequencies_160mhz(self):
+        clock = CLK_160_MHZ
+        nyquist_zone = numpy.array([[1] * S_pn] * N_pn)
+        spectral_inversion = numpy.array([[True] * S_pn] * N_pn)
+
+        self._verify_subband_frequencies(clock, nyquist_zone, spectral_inversion)
+
+    def test_subband_frequencies_mixed_fpga_settings(self):
+        """Test different settings for the FPGAs to verify the ordering."""
+
+        clock = CLK_200_MHZ
+        nyquist_zone = numpy.array([[1] * S_pn] * N_pn)
+        spectral_inversion = numpy.array([[True] * S_pn] * N_pn)
+
+        # change settings for FPGAs beyond 4
+        nyquist_zone[4:, :] = 0
+        spectral_inversion[4:, :] = False
+
+        self._verify_subband_frequencies(clock, nyquist_zone, spectral_inversion)
+
+    def test_subband_frequencies_mixed_input_settings(self):
+        """Test different settings for the inputs of the FPGAs to verify the ordering."""
+
+        clock = CLK_200_MHZ
+        nyquist_zone = numpy.array([[1] * S_pn] * N_pn)
+        spectral_inversion = numpy.array([[True] * S_pn] * N_pn)
+
+        # change settings for inputs beyond 4
+        nyquist_zone[:, 4:] = 0
+        spectral_inversion[:, 4:] = False
+
+        self._verify_subband_frequencies(clock, nyquist_zone, spectral_inversion)