I'd personally use a remote event inside of Replicated Storage, and invoke it using a server-script inside of the players tool.
When the player clicks, it fires the event to the players client and a LocalScript inside of the client listens for this and plays the sound.
Here's some example code:
local storage = game.ReplicatedStorage
local remoteEvent = storage:WaitForChild('Event_Name')
mouseclicked:connect(function()
remoteEvent:FireClient(player)
end)
remoteEvent.OnClientEvent:connect(function()
sound:Play()
end)
Now in order to prevent latency issues, I'd only fire it with either a debounce for semi-autos or firing it once whenever a player holds down the mouse and then re-firing it when the player releases the button.
Some links and references that would be helpful:
https://developer.roblox.com/en-us/api-reference/class/RemoteEvent
https://developer.roblox.com/en-us/api-reference/class/LocalScript
https://developer.roblox.com/en-us/api-reference/class/Script