diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 7ffa8c192c3f..f93149740207 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -458,6 +458,11 @@ struct mgmt_ctrl {
 	u16 opcode;
 };
 
+struct iso_ctrl {
+	u16 seq;
+	u8 have_seq:1;
+};
+
 struct bt_skb_cb {
 	u8 pkt_type;
 	u8 force_active;
@@ -469,6 +474,7 @@ struct bt_skb_cb {
 		struct hci_ctrl hci;
 		struct mgmt_ctrl mgmt;
 		struct scm_creds creds;
+		struct iso_ctrl iso;
 	};
 };
 #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
diff --git a/include/net/bluetooth/iso.h b/include/net/bluetooth/iso.h
index 3f4fe8b78e1b..a68ddd99232f 100644
--- a/include/net/bluetooth/iso.h
+++ b/include/net/bluetooth/iso.h
@@ -29,4 +29,7 @@ struct sockaddr_iso {
 	struct sockaddr_iso_bc iso_bc[];
 };
 
+/* ISO socket CMSG */
+#define ISO_CMSG_SEQ			0x01	/* u16 data */
+
 #endif /* __ISO_H */
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 34c8dca2069f..706784aa8bb4 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3330,6 +3330,7 @@ static void hci_queue_iso(struct hci_conn *conn, struct sk_buff_head *queue,
 {
 	struct hci_dev *hdev = conn->hdev;
 	struct sk_buff *list;
+	ktime_t now = ktime_get();
 	__u16 flags;
 
 	skb->len = skb_headlen(skb);
@@ -3346,6 +3347,7 @@ static void hci_queue_iso(struct hci_conn *conn, struct sk_buff_head *queue,
 		/* Non fragmented */
 		BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
 
+		skb_set_delivery_time(skb, now, true);
 		skb_queue_tail(queue, skb);
 	} else {
 		/* Fragmented */
@@ -3353,6 +3355,7 @@ static void hci_queue_iso(struct hci_conn *conn, struct sk_buff_head *queue,
 
 		skb_shinfo(skb)->frag_list = NULL;
 
+		skb_set_delivery_time(skb, now, true);
 		__skb_queue_tail(queue, skb);
 
 		do {
@@ -3365,6 +3368,7 @@ static void hci_queue_iso(struct hci_conn *conn, struct sk_buff_head *queue,
 
 			BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
 
+			skb_set_delivery_time(skb, now, true);
 			__skb_queue_tail(queue, skb);
 		} while (list);
 	}
@@ -3461,6 +3465,237 @@ static struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type,
 	return conn;
 }
 
+static unsigned int iso_group_id(struct hci_conn *conn)
+{
+	if (!conn)
+		return 0xff;
+
+	if (bacmp(&conn->dst, BDADDR_ANY))
+		return (u8)conn->iso_qos.ucast.cig;
+	else
+		return (u8)conn->iso_qos.bcast.big + 0x100;
+}
+
+static int iso_seq_cmp(u16 a, u16 b)
+{
+	u16 diff = a - b;
+
+	return (diff == 0) ? 0 : (diff < U16_MAX / 2) ? 1 : -1;
+}
+
+static struct hci_conn *hci_low_iso_group(struct hci_dev *hdev, u16 group_id,
+					  int pkt, int max_pkt,
+					  ktime_t *res_time)
+{
+	struct hci_conn_hash *h = &hdev->conn_hash;
+	struct hci_conn *c;
+	bool ready = true;
+	bool same_sent = true;
+	struct hci_conn *early_c = NULL;
+	ktime_t early_time = KTIME_MAX;
+	struct hci_conn *seq_c = NULL;
+	u16 seq = 0;
+	unsigned int sent = ~0;
+	int group_size = 0;
+
+	/* The controller may use packet arrival times to assign timestamps
+	 * (Core v5.4 Vol 6 Part G Sec 3.3). We should try to send packets that
+	 * correspond to same interval in ISO group at the same time, so that
+	 * streams in the group stay in sync with each other.
+	 *
+	 * User may attach a sequence number (seq) to each skb via cmsg.  We try
+	 * to send, within a group, the skb that have the same seq at the same
+	 * time.
+	 *
+	 * skb seq and ktime (when we received it from user) are used for
+	 * scheduling. The seq of a stream is the one of its first skb.
+	 *
+	 * First:
+	 *
+	 * - For each stream in a group, clear seq that are earlier than other
+	 *   seq in the group.
+	 *
+	 * - If all streams in a group have same seq, those streams are
+	 *   "ready".
+	 *
+	 * - If a stream in a group has no seq, that stream is "ready".
+	 *
+	 * Then:
+	 *
+	 * Select the "ready" stream that has earliest ktime, of those in all
+	 * groups.
+	 *
+	 * If the stream has seq (= its group as a whole is "ready"):
+	 *
+	 * - If controller does not have enough free packet slots to receive
+	 *   the whole group at once, but in principle can have enough slots,
+	 *   don't send anything and wait for queue to clear.
+	 *
+	 * - If conn->sent in the group are not equal, don't send anything
+	 *   and wait for queue to clear.
+	 *
+	 * The conn->sent one is important, and is what recovers synchronization
+	 * when the controller loses it. It appears that e.g. with Intel AX210
+	 * sometimes one of packets of a group, even when submitted immediately
+	 * after each other to all streams in a group, fails to be sent but is
+	 * left in the queue instead of being discarded. It gets postponed for
+	 * later, but this destroys synchronization between streams, and we have
+	 * to compensate for this if we see it.
+	 *
+	 * Core v5.4 Vol 6 Part G does not give much tools to do things properly
+	 * when HCI_LE_Read_ISO_TX_Sync does not work and we can't set
+	 * timestamps, hence the contortions here.
+	 */
+
+	/* called with rcu lock held */
+	list_for_each_entry_rcu(c, &h->list, list) {
+		struct sk_buff *skb;
+
+		if (c->type != ISO_LINK || c->state != BT_CONNECTED)
+			continue;
+		if (iso_group_id(c) != group_id)
+			continue;
+
+		++group_size;
+
+		if (sent == ~0)
+			sent = c->sent;
+		if (c->sent != sent)
+			same_sent = false;
+
+		if (skb_queue_empty(&c->data_q)) {
+			ready = false;
+			continue;
+		}
+
+		skb = skb_peek(&c->data_q);
+
+		/* Earliest skb */
+		if (!early_c || skb_get_ktime(skb) < early_time) {
+			early_c = c;
+			early_time = skb_get_ktime(skb);
+		}
+
+		if (bt_cb(skb)->iso.have_seq) {
+			u16 cseq = bt_cb(skb)->iso.seq;
+			int diff = iso_seq_cmp(cseq, seq);
+
+			if (seq_c && diff != 0)
+				ready = false;
+
+			/* Largest seq */
+			if (!seq_c || diff > 0) {
+				seq = cseq;
+				seq_c = c;
+			}
+		} else {
+			ready = false;
+		}
+	}
+
+	if (!early_c) {
+		*res_time = KTIME_MAX;
+		return NULL;
+	}
+
+	/* Group has seq and is ready? */
+	if (ready) {
+		*res_time = early_time;
+
+		/* Need to wait for queue to clear? */
+		if (!same_sent && pkt < max_pkt) {
+			BT_DBG("group %u !same_sent", group_id);
+			return NULL;
+		}
+		if (group_size <= max_pkt && group_size > pkt) {
+			BT_DBG("group %u wait queue", group_id);
+			return NULL;
+		}
+
+		BT_DBG("group %u ready %u", group_id, seq);
+	} else {
+		early_c = NULL;
+		early_time = KTIME_MAX;
+
+		if (seq_c)
+			BT_DBG("group %u seq %u", group_id, seq);
+	}
+
+	list_for_each_entry_rcu(c, &h->list, list) {
+		struct sk_buff *skb;
+
+		if (c->type != ISO_LINK || c->state != BT_CONNECTED)
+			continue;
+		if (iso_group_id(c) != group_id || skb_queue_empty(&c->data_q))
+			continue;
+
+		skb = skb_peek(&c->data_q);
+
+		/* Clear seq */
+		if (ready) {
+			bt_cb(skb)->iso.have_seq = false;
+			skb_set_delivery_time(skb, early_time, true);
+		} else if (bt_cb(skb)->iso.have_seq && seq_c) {
+			u16 cseq = bt_cb(skb)->iso.seq;
+
+			if (cseq != seq)
+				bt_cb(skb)->iso.have_seq = false;
+		}
+
+		/* Conn with earliest non-seq skb */
+		if (!bt_cb(skb)->iso.have_seq) {
+			if (!early_c || skb_get_ktime(skb) < early_time) {
+				early_c = c;
+				early_time = skb_get_ktime(skb);
+			}
+		}
+	}
+
+	*res_time = early_time;
+	return early_c;
+}
+
+static struct hci_conn *hci_low_iso(struct hci_dev *hdev, int pkt, int max_pkt)
+{
+	struct hci_conn_hash *h = &hdev->conn_hash;
+	struct hci_conn *c;
+	unsigned long group_done[BITS_TO_LONGS(0x200)];
+	ktime_t min = KTIME_MAX;
+	struct hci_conn *conn = NULL;
+
+	/* See hci_low_iso_group() for explanation */
+
+	bitmap_zero(group_done, 0x200);
+
+	rcu_read_lock();
+
+	list_for_each_entry_rcu(c, &h->list, list) {
+		struct hci_conn *c2;
+		ktime_t t;
+
+		if (c->type != ISO_LINK || c->state != BT_CONNECTED)
+			continue;
+		if (test_bit(iso_group_id(c), group_done))
+			continue;
+
+		c2 = hci_low_iso_group(hdev, iso_group_id(c), pkt, max_pkt, &t);
+		if (t < min) {
+			conn = c2;
+			min = t;
+		}
+
+		BT_DBG("group %u conn %p", iso_group_id(c), c2);
+
+		set_bit(iso_group_id(c), group_done);
+	}
+
+	rcu_read_unlock();
+
+	BT_DBG("conn %p", conn);
+
+	return conn;
+}
+
 static void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
 {
 	struct hci_conn_hash *h = &hdev->conn_hash;
@@ -3846,12 +4081,11 @@ static void hci_sched_le(struct hci_dev *hdev)
 		hci_prio_recalculate(hdev, LE_LINK);
 }
 
-/* Schedule CIS */
+/* Schedule CIS/BIS */
 static void hci_sched_iso(struct hci_dev *hdev)
 {
 	struct hci_conn *conn;
-	struct sk_buff *skb;
-	int quote, *cnt;
+	unsigned int max, *cnt;
 
 	BT_DBG("%s", hdev->name);
 
@@ -3860,16 +4094,20 @@ static void hci_sched_iso(struct hci_dev *hdev)
 
 	cnt = hdev->iso_pkts ? &hdev->iso_cnt :
 		hdev->le_pkts ? &hdev->le_cnt : &hdev->acl_cnt;
-	while (*cnt && (conn = hci_low_sent(hdev, ISO_LINK, &quote))) {
-		while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
-			BT_DBG("skb %p len %d", skb, skb->len);
-			hci_send_frame(hdev, skb);
+	max = (cnt == &hdev->iso_cnt) ? hdev->iso_pkts : 0;
 
-			conn->sent++;
-			if (conn->sent == ~0)
-				conn->sent = 0;
-			(*cnt)--;
-		}
+	while (*cnt && (conn = hci_low_iso(hdev, *cnt, max))) {
+		struct sk_buff *skb;
+
+		skb = skb_dequeue(&conn->data_q);
+
+		BT_DBG("skb %p len %d", skb, skb->len);
+		hci_send_frame(hdev, skb);
+
+		conn->sent++;
+		if (conn->sent == ~0)
+			conn->sent = 0;
+		(*cnt)--;
 	}
 }
 
diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c
index 04f6572d35f1..58d9ec8ce298 100644
--- a/net/bluetooth/iso.c
+++ b/net/bluetooth/iso.c
@@ -1240,12 +1240,48 @@ static int iso_sock_getname(struct socket *sock, struct sockaddr *addr,
 	return sizeof(struct sockaddr_iso);
 }
 
+static int iso_cmsg_parse_one(struct cmsghdr *cmsg, struct iso_ctrl *ctrl)
+{
+	switch (cmsg->cmsg_type) {
+	case ISO_CMSG_SEQ:
+		if (cmsg->cmsg_len != CMSG_LEN(sizeof(ctrl->seq)))
+			return -EINVAL;
+
+		memcpy(&ctrl->seq, CMSG_DATA(cmsg), sizeof(ctrl->seq));
+		ctrl->have_seq = true;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int iso_cmsg_parse(struct sock *sk, struct msghdr *msg, struct iso_ctrl *ctrl)
+{
+	struct cmsghdr *cmsg;
+	int err;
+
+	for_each_cmsghdr(cmsg, msg) {
+		if (!CMSG_OK(msg, cmsg))
+			return -EINVAL;
+
+		if (cmsg->cmsg_level != SOL_BLUETOOTH)
+			continue;
+
+		err = iso_cmsg_parse_one(cmsg, ctrl);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
 static int iso_sock_sendmsg(struct socket *sock, struct msghdr *msg,
 			    size_t len)
 {
 	struct sock *sk = sock->sk;
 	struct sk_buff *skb, **frag;
 	size_t mtu;
+	struct iso_ctrl ctrl = {};
 	int err;
 
 	BT_DBG("sock %p, sk %p", sock, sk);
@@ -1257,6 +1293,12 @@ static int iso_sock_sendmsg(struct socket *sock, struct msghdr *msg,
 	if (msg->msg_flags & MSG_OOB)
 		return -EOPNOTSUPP;
 
+	if (msg->msg_controllen) {
+		err = iso_cmsg_parse(sk, msg, &ctrl);
+		if (err < 0)
+			return err;
+	}
+
 	lock_sock(sk);
 
 	if (sk->sk_state != BT_CONNECTED) {
@@ -1274,6 +1316,8 @@ static int iso_sock_sendmsg(struct socket *sock, struct msghdr *msg,
 
 	len -= skb->len;
 
+	bt_cb(skb)->iso = ctrl;
+
 	BT_DBG("skb %p len %d", sk, skb->len);
 
 	/* Continuation fragments */
@@ -1294,6 +1338,8 @@ static int iso_sock_sendmsg(struct socket *sock, struct msghdr *msg,
 		skb->len += tmp->len;
 		skb->data_len += tmp->len;
 
+		bt_cb(tmp)->iso.have_seq = false;
+
 		BT_DBG("frag %p len %d", *frag, tmp->len);
 
 		frag = &(*frag)->next;
