Rafinha put Xavi’s side ahead with a header from Sergio Busquets’ overhead kick.
They looked set to take control of the game when they won a penalty in the second half, but Ferran Torres hit the post against his old side.
Ansu Fati fired home a minute later and Barcelona finished with 10 men after Ronald Araujo was sent off.
The defender of “Barça” received a straight red card for a professional foul on Hugo Duro, who ran into Jules Kunde’s unsuccessful header.
Barcelona goalkeeper Marc-Andre ter Stegen kept his 18th clean sheet in 24 La Liga games this season and had to make just one save, keeping out Justin Kluivert’s 20-yard shot with seconds remaining.
Barca briefly trailed by 10 points, and Real managed to cut that gap to just nine points after a goalless draw at Real Betis later on Sunday.
Barcelona were without top three scorers Robert Lewandowski, Ousmane Dembele and Pedro through injury and head coach Xavi watched from the stands as he served his suspension.
Valencia remains in the relegation zone after the defeat.