I know that the DHCP is used to assign an IP address to the client and hence the only possible way to establish the connection is to listen on a specific port. But is there any specific reason behind choosing 67 and 68?
DHCP is based on the earlier BOOTP protocol which uses well known port numbers for both server and client instead of an ephemeral port. The server and the client communicate via broadcast and the server broadcasts the offered IP address to the client on UDP port 68. The use of a well known port on the client's side is introduced to tackle the problem associated with this broadcast, which we will describe below.
Let's assume that host A is using the BOOTP client on ephemeral port 1883, and host B (which is on the same network) is using MQTT client on the same port. Now when the BOOTP server sends a broadcast reply message with the broadcast IP address 255.255.255.255 and destination port no. 1883, then host A will accept the correct message on its DHCP client on the application layer. But, the MQTT client which is running on the application layer of host B will get an incorrect message. The use of an well known port (in our case 68) prevents the use of the same two destination port numbers and hence it prohibits other protocols from using the same port which is already in use by another protocol. In simple words, it prevents an application from getting a message from a completely different protocol.
For more details I would recommend you to go through the RFC 2131.
DHCP is based on BOOTP which was created in 1985.
BOOTP uses TFTP as the file transfer protocol.
TFTP was created in 1981 and uses port 69, so it was a thing of using the nearest non-used ports (68 and 67).